terminal/src/cascadia/TerminalApp/TerminalPage.cpp

3429 lines
137 KiB
C++
Raw Normal View History

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "TerminalPage.h"
#include "Utils.h"
Add support for new panes with specifc profiles and other settings overrides (#3825) ## Summary of the Pull Request This enables the user to set a number of extra settings in the `NewTab` and `SplitPane` `ShortcutAction`s, that enable customizing how a new terminal is created at runtime. The following four properties were added: * `profile` * `commandline` * `tabTitle` * `startingDirectory` `profile` can be used with either a GUID or the name of a profile, and the action will launch that profile instead of the default. `commandline`, `tabTitle`, and `startingDirectory` can all be used to override the profile's values of those settings. This will be more useful for #607. With this PR, you can make bindings like the following: ```json { "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" } }, { "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "vertical", "profile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" } }, { "keys": ["ctrl+c"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile1" } }, { "keys": ["ctrl+d"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile2" } }, { "keys": ["ctrl+e"], "command": { "action": "splitPane", "split": "horizontal", "commandline": "foo.exe" } }, { "keys": ["ctrl+f"], "command": { "action": "splitPane", "split": "horizontal", "profile": "profile1", "commandline": "foo.exe" } }, { "keys": ["ctrl+g"], "command": { "action": "newTab" } }, { "keys": ["ctrl+h"], "command": { "action": "newTab", "startingDirectory": "c:\\foo" } }, { "keys": ["ctrl+i"], "command": { "action": "newTab", "profile": "profile2", "startingDirectory": "c:\\foo" } }, { "keys": ["ctrl+j"], "command": { "action": "newTab", "tabTitle": "bar" } }, { "keys": ["ctrl+k"], "command": { "action": "newTab", "profile": "profile2", "tabTitle": "bar" } }, { "keys": ["ctrl+l"], "command": { "action": "newTab", "profile": "profile1", "tabTitle": "bar", "startingDirectory": "c:\\foo", "commandline":"foo.exe" } } ``` ## References This is a lot of work that was largely started in pursuit of #607. We want people to be able to override these properties straight from the commandline. While they may not make as much sense as keybindings like this, they'll make more sense as commandline arguments. ## PR Checklist * [x] Closes #998 * [x] I work here * [x] Tests added/passed * [x] Requires documentation to be updated ## Validation Steps Performed There are tests 🎉 Manually added some bindings, they opened the correct profiles in panes/tabs
2019-12-09 14:02:29 +01:00
#include "../../types/inc/utils.hpp"
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
#include <filesystem>
Introduce a WinRT utils library and "checked resources" (#3350) This commit introduces a C++/WinRT utility library and moves ScopedResourceLoader into it. I decided to get uppity and introduce something I like to call "checked resources." The idea is that every resource reference from a library is knowable at compile time, and we should be able to statically ensure that all resources exist. This is a system that lets us immediately failfast (on launch) when a library makes a static reference to a resource that doesn't exist at runtime. It exposes two new (preprocessor) APIs: * `RS_(wchar_t)`: loads a localizable string resource by name. * `USES_RESOURCE(wchar_t)`: marks a resource key as used, but is intended for loading images or passing static resource keys as parameters to functions that will look them up later. Resource checking relies on diligent use of `USES_RESOURCE()` and `RS_()` (which uses `USES_RESOURCE`), but can make sure we don't ship something that'll blow up at runtime. It works like this: **IN DEBUG MODE** - All resource names referenced through `USES_RESOURCE()` are emitted alongside their referencing filenames and line numbers into a static section of the binary. That section is named `.util$res$m`. - We emit two sentinel values into two different sections, `.util$res$a` and `.util$res$z`. - The linker sorts all sections alphabetically before crushing them together into the final binary. - When we first construct a library's scoped resource loader, we iterate over every resource reference between `$a` and `$z` and check residency. **IN RELEASE MODE** - All checked resource code is compiled out. Fixes #2146. Macros are the only way to do something this cool, incidentally. ## Validation Steps Performed Made references to a bunch of bad resources, tried to break it a lot. It looks like this when it fails: ### App.cpp ``` 36 static const std::array<std::wstring_view, 2> settingsLoadErrorsLabels { 37 USES_RESOURCE(L"NoProfilesText"), 38 USES_RESOURCE(L"AllProfilesHiddenText_HA_JUST_KIDDING") 39 }; ``` ``` WinRTUtils\LibraryResources.cpp(68)\TerminalApp.dll: FailFast(1) tid(1034) 8000FFFF Catastrophic failure Msg:[Resource AllProfilesHiddenText_HA_JUST_KIDDING not found in scope TerminalApp/Resources (App.cpp:38)] [EnsureAllResourcesArePresent] ```
2019-11-01 23:47:05 +01:00
#include <LibraryResources.h>
#include "TerminalPage.g.cpp"
#include <winrt/Windows.Storage.h>
#include "TabRowControl.h"
#include "ColorHelper.h"
#include "DebugTapConnection.h"
#include "SettingsTab.h"
Add support for renaming windows (#9662) ## Summary of the Pull Request This PR adds support for renaming windows. ![window-renaming-000](https://user-images.githubusercontent.com/18356694/113034344-9a30be00-9157-11eb-9443-975f3c294f56.gif) ![window-renaming-001](https://user-images.githubusercontent.com/18356694/113034452-b5033280-9157-11eb-9e35-e5ac80fef0bc.gif) It does so through two new actions: * `renameWindow` takes a `name` parameter, and attempts to set the window's name to the provided name. This is useful if you always want to hit <kbd>F3</kbd> and rename a window to "foo" (READ: probably not that useful) * `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a `TextBox`. When the user hits Ok, it'll request a rename for the provided value. This lets the user pick a new name for the window at runtime. In both cases, if there's already a window with that name, then the monarch will reject the rename, and pop a `Toast` in the window informing the user that the rename failed. Nifty! ## References * Builds on the toasts from #9523 * #5000 - process model megathread ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747 * [x] I work here * [x] Tests addded (and pass with the help of #9660) * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews. > PAIN: We can't immediately focus the textbox in the TeachingTip. It's > not technically focusable until it is opened. However, it doesn't > provide an even tto tell us when it is opened. That's tracked in > microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to > click on the text box manually. > We're also not using a ContentDialog for this, because in Xaml > Islands a text box in a ContentDialog won't recieve _any_ keypresses. > Fun! ## Validation Steps Performed I've been playing with ```json { "keys": "f1", "command": "identifyWindow" }, { "keys": "f2", "command": "identifyWindows" }, { "keys": "f3", "command": "openWindowRenamer" }, { "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } }, { "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } }, ``` and they seem to work as expected
2021-04-02 18:00:04 +02:00
#include "RenameWindowRequestedArgs.g.cpp"
2021-04-29 00:13:28 +02:00
#include "../inc/WindowingBehavior.h"
Add Dynamic Profile Generators (#2603) _**This PR targets the #2515 PR**_. It does that for the sake of diffing. When this PR and #2515 are both ready, I'll merge #2515 first, then change the target of this branch, and merge this one. <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR adds support for "dynamic profiles", in accordance with the [Cascading Settings Spec](https://github.com/microsoft/terminal/blob/master/doc/cascadia/Cascading-Default-Settings.md#dynamic-profiles). Currently, we have three types of default profiles that fit the category of dynamic profile generators. These are profiles that we want to create on behalf of the user, but require runtime information to be able to create correctly. Because they require runtime information, we can't ship a static version of these profiles as a part of `defaults.json`. These three profile generators are: * The Powershell Core generator * The WSL Distro generator * The Azure Cloud Shell generator <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #754 * [x] I work here * [x] look at all these **Tests** * [x] Requires documentation to be updated - This is done as part of the parent PR <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments We want to be able to enable the user to edit dynamic profiles that are generated from DPGs. When dynamic profiles are added, we'll add entries for them to the user's `profiles.json`. We do this _without re-serializing_ the settings. Instead, we insert a partial serialization for the profile into the user's settings. ### Remaining TODOs: * Make sure that dynamic profiles appear in the right place in the order of profiles -> #2722 * [x] don't serialize the `colorTable` key for dynamic profiles. * [x] re-parse the user settings string if we've changed it. * Handle changing the default profile to pwsh if it exists on first launch, or file a follow-up issue -> #2721 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed <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 * Start dynamically creating profiles * Give the inbox generators a namespace and generally hack this a lot less * 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 * Serialize the source key * Make the Azure cloud shell a dynamic profile * Make the built-in namespaces public * Add a mechanism for quick-diffing a profile This will be used to generate the json snippets for dynamically generated profiles. * Generate partial serializations of dynamic profiles _not_ in the user settings * Start writing tests for generating dyn profiles * dyn profiles generate GUIDs based on _source * we won't run DPGs when they'd disabled? * Add more DPG tests - TestDontRunDisabledGenerators * Don't layer profiles with a source that's also different * Add another test, DoLayerUserProfilesOnDynamicsWhenSourceMatches * Actually insert new dynamic profiles into the file * Minor cleanup of `Profile::ShouldBeLayered` * Migrate legacy profiles gracefully * using namespace winrt::Windows::UI::Xaml; * _Only_ layer dynamic profiles from user settings, never create * Write a test for migrating dynamic profiles * Comments for dayssssss * 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 * Don't layer a profile if the json doesn't have a GUID * Fix a test I unfixed * get rid of extraneous bois{}; * Piles of PR feedback * Collection of PR nits * PR nits * Fix a typo; Update the defaults to match #2378 * Tiny nits * In-den-taition! * Some typos, PR nits * Fix this broken defaults case * Apply suggestions from code review Co-Authored-By: Carlos Zamora <carlos.zamora@microsoft.com> * PR nits
2019-09-16 22:34:27 +02:00
#include <til/latch.h>
using namespace winrt;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::System;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
using namespace winrt::Windows::UI::Text;
using namespace winrt::Microsoft::Terminal;
Rename `Microsoft.Terminal.TerminalControl` to `.Control`; Split into dll & lib (#9472) **BE NOT AFRAID**. I know that there's 107 files in this PR, but almost all of it is just find/replacing `TerminalControl` with `Control`. This is the start of the work to move TermControl into multiple pieces, for #5000. The PR starts this work by: * Splits `TerminalControl` into separate lib and dll projects. We'll want control tests in the future, and for that, we'll need a lib. * Moves `ICoreSettings` back into the `Microsoft.Terminal.Core` namespace. We'll have other types in there soon too. * I could not tell you why this works suddenly. New VS versions? New cppwinrt version? Maybe we're just better at dealing with mdmerge bugs these days. * RENAMES `Microsoft.Terminal.TerminalControl` to `Microsoft.Terminal.Control`. This touches pretty much every file in the sln. Sorry about that (not sorry). An upcoming PR will move much of the logic in TermControl into a new `ControlCore` class that we'll add in `Microsoft.Terminal.Core`. `ControlCore` will then be unittest-able in the `UnitTests_TerminalCore`, which will help prevent regressions like #9455 ## Detailed Description of the Pull Request / Additional comments You're really gonna want to clean the sln first, then merge this into your branch, then rebuild. It's very likely that old winmds will get left behind. If you see something like ``` Error MDM2007 Cannot create type Microsoft.Terminal.TerminalControl.KeyModifiers in read-only metadata file Microsoft.Terminal.TerminalControl. ``` then that's what happened to you.
2021-03-17 21:47:24 +01:00
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::TerminalConnection;
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace ::TerminalApp;
Add support for new panes with specifc profiles and other settings overrides (#3825) ## Summary of the Pull Request This enables the user to set a number of extra settings in the `NewTab` and `SplitPane` `ShortcutAction`s, that enable customizing how a new terminal is created at runtime. The following four properties were added: * `profile` * `commandline` * `tabTitle` * `startingDirectory` `profile` can be used with either a GUID or the name of a profile, and the action will launch that profile instead of the default. `commandline`, `tabTitle`, and `startingDirectory` can all be used to override the profile's values of those settings. This will be more useful for #607. With this PR, you can make bindings like the following: ```json { "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" } }, { "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "vertical", "profile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" } }, { "keys": ["ctrl+c"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile1" } }, { "keys": ["ctrl+d"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile2" } }, { "keys": ["ctrl+e"], "command": { "action": "splitPane", "split": "horizontal", "commandline": "foo.exe" } }, { "keys": ["ctrl+f"], "command": { "action": "splitPane", "split": "horizontal", "profile": "profile1", "commandline": "foo.exe" } }, { "keys": ["ctrl+g"], "command": { "action": "newTab" } }, { "keys": ["ctrl+h"], "command": { "action": "newTab", "startingDirectory": "c:\\foo" } }, { "keys": ["ctrl+i"], "command": { "action": "newTab", "profile": "profile2", "startingDirectory": "c:\\foo" } }, { "keys": ["ctrl+j"], "command": { "action": "newTab", "tabTitle": "bar" } }, { "keys": ["ctrl+k"], "command": { "action": "newTab", "profile": "profile2", "tabTitle": "bar" } }, { "keys": ["ctrl+l"], "command": { "action": "newTab", "profile": "profile1", "tabTitle": "bar", "startingDirectory": "c:\\foo", "commandline":"foo.exe" } } ``` ## References This is a lot of work that was largely started in pursuit of #607. We want people to be able to override these properties straight from the commandline. While they may not make as much sense as keybindings like this, they'll make more sense as commandline arguments. ## PR Checklist * [x] Closes #998 * [x] I work here * [x] Tests added/passed * [x] Requires documentation to be updated ## Validation Steps Performed There are tests 🎉 Manually added some bindings, they opened the correct profiles in panes/tabs
2019-12-09 14:02:29 +01:00
using namespace ::Microsoft::Console;
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
using namespace std::chrono_literals;
#define HOOKUP_ACTION(action) _actionDispatch->action({ this, &TerminalPage::_Handle##action });
namespace winrt
{
namespace MUX = Microsoft::UI::Xaml;
namespace WUX = Windows::UI::Xaml;
using IInspectable = Windows::Foundation::IInspectable;
using VirtualKeyModifiers = Windows::System::VirtualKeyModifiers;
}
namespace winrt::TerminalApp::implementation
{
Introduce a WinRT utils library and "checked resources" (#3350) This commit introduces a C++/WinRT utility library and moves ScopedResourceLoader into it. I decided to get uppity and introduce something I like to call "checked resources." The idea is that every resource reference from a library is knowable at compile time, and we should be able to statically ensure that all resources exist. This is a system that lets us immediately failfast (on launch) when a library makes a static reference to a resource that doesn't exist at runtime. It exposes two new (preprocessor) APIs: * `RS_(wchar_t)`: loads a localizable string resource by name. * `USES_RESOURCE(wchar_t)`: marks a resource key as used, but is intended for loading images or passing static resource keys as parameters to functions that will look them up later. Resource checking relies on diligent use of `USES_RESOURCE()` and `RS_()` (which uses `USES_RESOURCE`), but can make sure we don't ship something that'll blow up at runtime. It works like this: **IN DEBUG MODE** - All resource names referenced through `USES_RESOURCE()` are emitted alongside their referencing filenames and line numbers into a static section of the binary. That section is named `.util$res$m`. - We emit two sentinel values into two different sections, `.util$res$a` and `.util$res$z`. - The linker sorts all sections alphabetically before crushing them together into the final binary. - When we first construct a library's scoped resource loader, we iterate over every resource reference between `$a` and `$z` and check residency. **IN RELEASE MODE** - All checked resource code is compiled out. Fixes #2146. Macros are the only way to do something this cool, incidentally. ## Validation Steps Performed Made references to a bunch of bad resources, tried to break it a lot. It looks like this when it fails: ### App.cpp ``` 36 static const std::array<std::wstring_view, 2> settingsLoadErrorsLabels { 37 USES_RESOURCE(L"NoProfilesText"), 38 USES_RESOURCE(L"AllProfilesHiddenText_HA_JUST_KIDDING") 39 }; ``` ``` WinRTUtils\LibraryResources.cpp(68)\TerminalApp.dll: FailFast(1) tid(1034) 8000FFFF Catastrophic failure Msg:[Resource AllProfilesHiddenText_HA_JUST_KIDDING not found in scope TerminalApp/Resources (App.cpp:38)] [EnsureAllResourcesArePresent] ```
2019-11-01 23:47:05 +01:00
TerminalPage::TerminalPage() :
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
_mruTabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
Propagate IslandWindow's HWND into any component that needs it (#8391) This fixes the issue with the settings UI where clicking the browse buttons would cause an exception to be thrown when we tried to display a picker without an originating HWND. It turns out that pickers need a hosting/parent window, and Xaml Islands doesn't furnish us with a CoreWindow that's set up for that use case. Alas! Raymond Chen's [blog post on the matter] suggests that we should hand the HWND off through some classic COM interface. To do that properly, Terminal's various components need to implement that interface and propagate the HWND down where it's needed. Thanks to a [Xaml compiler issue], we can't actually do that. To work around that, we've begged and borrowed different methods for pushing HWNDs around: 1. Using IInitializeWithWindow in secret 2. A member that takes a uint64 3. An interface that offers a function that will "wire up" the HWND. I chose (1) because AppHost can implement IInitializeWithWindow, but TerminalPage cannot. We're just pretending that TerminalPage _can_. I chose (2) because none of the Xaml types in TerminalSettingsEditor can implement the interface thanks to the aforementioned compiler issue, but we don't have an escape hatch like AppHost that lives in the same module and can help us do the propagation. I chose (3) because I didn't want to commit the same sin as (2) _seven times_ for every different type of settings page that exists. (3) is backed by "IHostedInWindow", and anybody who knows they have to use IInitializeWithWindow to tie an HWND to an object can call IHostedInWindow.TryPropagateHostingWindow() on that object. House of cards. [Xaml compiler issue]: https://github.com/microsoft/microsoft-ui-xaml/issues/3331 [blog post on the matter]: https://devblogs.microsoft.com/oldnewthing/20190412-00/?p=102413 (cherry picked from commit f9fc9861a111925347f0362ba0fd9a14fb0765c9)
2020-11-30 20:51:42 +01:00
_startupActions{ winrt::single_threaded_vector<ActionAndArgs>() },
_hostingHwnd{}
{
InitializeComponent();
}
Propagate IslandWindow's HWND into any component that needs it (#8391) This fixes the issue with the settings UI where clicking the browse buttons would cause an exception to be thrown when we tried to display a picker without an originating HWND. It turns out that pickers need a hosting/parent window, and Xaml Islands doesn't furnish us with a CoreWindow that's set up for that use case. Alas! Raymond Chen's [blog post on the matter] suggests that we should hand the HWND off through some classic COM interface. To do that properly, Terminal's various components need to implement that interface and propagate the HWND down where it's needed. Thanks to a [Xaml compiler issue], we can't actually do that. To work around that, we've begged and borrowed different methods for pushing HWNDs around: 1. Using IInitializeWithWindow in secret 2. A member that takes a uint64 3. An interface that offers a function that will "wire up" the HWND. I chose (1) because AppHost can implement IInitializeWithWindow, but TerminalPage cannot. We're just pretending that TerminalPage _can_. I chose (2) because none of the Xaml types in TerminalSettingsEditor can implement the interface thanks to the aforementioned compiler issue, but we don't have an escape hatch like AppHost that lives in the same module and can help us do the propagation. I chose (3) because I didn't want to commit the same sin as (2) _seven times_ for every different type of settings page that exists. (3) is backed by "IHostedInWindow", and anybody who knows they have to use IInitializeWithWindow to tie an HWND to an object can call IHostedInWindow.TryPropagateHostingWindow() on that object. House of cards. [Xaml compiler issue]: https://github.com/microsoft/microsoft-ui-xaml/issues/3331 [blog post on the matter]: https://devblogs.microsoft.com/oldnewthing/20190412-00/?p=102413 (cherry picked from commit f9fc9861a111925347f0362ba0fd9a14fb0765c9)
2020-11-30 20:51:42 +01:00
// Method Description:
// - implements the IInitializeWithWindow interface from shobjidl_core.
HRESULT TerminalPage::Initialize(HWND hwnd)
{
_hostingHwnd = hwnd;
return S_OK;
}
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
// Function Description:
// - Recursively check our commands to see if there's a keybinding for
// exactly their action. If there is, label that command with the text
// corresponding to that key chord.
// - Will recurse into nested commands as well.
// Arguments:
// - settings: The settings who's keybindings we should use to look up the key chords from
// - commands: The list of commands to label.
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
static void _recursiveUpdateCommandKeybindingLabels(CascadiaSettings settings,
IMapView<winrt::hstring, Command> commands)
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
{
for (const auto& nameAndCmd : commands)
{
const auto& command = nameAndCmd.Value();
if (command.HasNestedCommands())
{
_recursiveUpdateCommandKeybindingLabels(settings, command.NestedCommands());
}
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
else
{
// If there's a keybinding that's bound to exactly this command,
// then get the keychord and display it as a
// part of the command in the UI.
// We specifically need to do this for nested commands.
const auto keyChord{ settings.ActionMap().GetKeyBindingForAction(command.ActionAndArgs().Action(), command.ActionAndArgs().Args()) };
command.RegisterKey(keyChord);
}
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
}
}
void TerminalPage::SetSettings(CascadiaSettings settings, bool needRefreshUI)
{
_settings = settings;
// Make sure to _UpdateCommandsForPalette before
// _RefreshUIForSettingsReload. _UpdateCommandsForPalette will make
// sure the KeyChordText of Commands is updated, which needs to
// happen before the Settings UI is reloaded and tries to re-read
// those values.
_UpdateCommandsForPalette();
CommandPalette().SetActionMap(_settings.ActionMap());
if (needRefreshUI)
{
_RefreshUIForSettingsReload();
}
// Upon settings update we reload the system settings for scrolling as well.
// TODO: consider reloading this value periodically.
_systemRowsToScroll = _ReadSystemRowsToScroll();
}
bool TerminalPage::IsElevated() const noexcept
{
// use C++11 magic statics to make sure we only do this once.
// This won't change over the lifetime of the application
static const bool isElevated = []() {
// *** THIS IS A SINGLETON ***
auto result = false;
// GH#2455 - Make sure to try/catch calls to Application::Current,
// because that _won't_ be an instance of TerminalApp::App in the
// LocalTests
try
{
result = ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Logic().IsElevated();
}
CATCH_LOG();
return result;
}();
return isElevated;
}
void TerminalPage::Create()
{
// Hookup the key bindings
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
_HookupKeyBindings(_settings.ActionMap());
_tabContent = this->TabContent();
_tabRow = this->TabRow();
_tabView = _tabRow.TabView();
_rearranging = false;
const auto isElevated = IsElevated();
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
if (_settings.GlobalSettings().UseAcrylicInTabRow())
{
const auto res = Application::Current().Resources();
const auto lightKey = winrt::box_value(L"Light");
const auto darkKey = winrt::box_value(L"Dark");
const auto tabViewBackgroundKey = winrt::box_value(L"TabViewBackground");
for (auto const& dictionary : res.MergedDictionaries())
{
// Don't change MUX resources
if (dictionary.Source())
{
continue;
}
for (auto const& kvPair : dictionary.ThemeDictionaries())
{
const auto themeDictionary = kvPair.Value().as<winrt::Windows::UI::Xaml::ResourceDictionary>();
if (themeDictionary.HasKey(tabViewBackgroundKey))
{
const auto backgroundSolidBrush = themeDictionary.Lookup(tabViewBackgroundKey).as<Media::SolidColorBrush>();
const til::color backgroundColor = backgroundSolidBrush.Color();
const auto acrylicBrush = Media::AcrylicBrush();
acrylicBrush.BackgroundSource(Media::AcrylicBackgroundSource::HostBackdrop);
acrylicBrush.FallbackColor(backgroundColor);
acrylicBrush.TintColor(backgroundColor);
acrylicBrush.TintOpacity(0.5);
themeDictionary.Insert(tabViewBackgroundKey, acrylicBrush);
}
}
}
}
_tabRow.PointerMoved({ get_weak(), &TerminalPage::_RestorePointerCursorHandler });
_tabView.CanReorderTabs(!isElevated);
_tabView.CanDragTabs(!isElevated);
minor refactor: Move Tab management into its own file (#9629) I think we can all agree that `TerminalPage.cpp` is an unruly beast of a file. It's got everything. It does everything. It can sometimes be a bit hard to work with, because of simply how big it is. This PR tries to alleviate this by making `TerminalPage.cpp` just a little smaller. It does so by moving pretty much everything related to tab management into its own file, `TabManagement.cpp`. These methods that have moved are all the same as they were before, and they're still members of `TerminalPage`. But now they're all in one place. I tried to move all the references to `_tabs` in `TerminalPage.cpp`, but there's still a few that I left behind. Mostly because I felt that moving those would be too gnarly a code change for an otherwise simple cut&paste PR. There are a few new methods I introduced: * `_TabDragStarted` and `_TabDragCompleted`: These were lambdas before, promoted to full methods. * `_DismissTabContextMenus`: Remove all the right-click context menus from the tabs * `_FocusCurrentTab`: This one's a bit trickier, we were actually doing this in a few different places, so I tried consolidating. * `_HasMultipleTabs`: This doesn't need explaining. * `_RemoveAllTabs`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` * `_ResizeTabContent`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` In the future, some enterprising young soul could try promoting that file to its own class, and hiding `_tabs` (and `_mruTabs`) inside it. Probably would need to take a reference to TerminalPage's `_tabView` and `_newTabButton`. I'm not doing that right now, because I already hate the idea of the ... > 920 additions and 847 deletions. ... I'm making you look at already. ## Other thoughts Some of the calls might be a little arbitrary - `_OpenNewTab` and `_CreateNewTabFromSettings` probably should stay in `TerminalPage`? Or at least elements of those might need to get split up better. Similarly `TerminalPage::_OpenSettingsUI` stayed in `TerminalPage.cpp`, but it does a lot of the same work as `_CreateNewTabFromSettings`. I'm not saying this is the definitive places for these methods - it's code we're working with, not stone ☺️
2021-03-29 21:53:39 +02:00
_tabView.TabDragStarting({ get_weak(), &TerminalPage::_TabDragStarted });
_tabView.TabDragCompleted({ get_weak(), &TerminalPage::_TabDragCompleted });
auto tabRowImpl = winrt::get_self<implementation::TabRowControl>(_tabRow);
_newTabButton = tabRowImpl->NewTabButton();
if (_settings.GlobalSettings().ShowTabsInTitlebar())
{
// Remove the TabView from the page. We'll hang on to it, we need to
// put it in the titlebar.
uint32_t index = 0;
if (this->Root().Children().IndexOf(_tabRow, index))
{
this->Root().Children().RemoveAt(index);
}
// Inform the host that our titlebar content has changed.
_SetTitleBarContentHandlers(*this, _tabRow);
}
// Hookup our event handlers to the ShortcutActionDispatch
_RegisterActionCallbacks();
// Hook up inbound connection event handler
ConptyConnection::NewConnection({ this, &TerminalPage::_OnNewConnection });
//Event Bindings (Early)
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
_newTabButton.Click([weakThis{ get_weak() }](auto&&, auto&&) {
Fixed self reference capture in Tab and TerminalPage (#3835) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Every lambda capture in `Tab` and `TerminalPage` has been changed from capturing raw `this` to `std::weak_ptr<Tab>` or `winrt::weak_ref<TerminalPage>`. Lambda bodies have been changed to check the weak reference before use. Capturing raw `this` in `Tab`'s [title change event handler](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/Tab.cpp#L299) was the root cause of #3776, and is fixed in this PR among other instance of raw `this` capture. The lambda fixes to `TerminalPage` are unrelated to the core issue addressed in the PR checklist. Because I was already editing `TerminalPage`, figured I'd do a [weak_ref pass](https://github.com/microsoft/terminal/issues/3776#issuecomment-560575575). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3776, potentially #2248, likely closes others * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3776 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments `Tab` now inherits from `enable_shared_from_this`, which enable accessing `Tab` objects as `std::weak_ptr<Tab>` objects. All instances of lambdas capturing `this` now capture `std::weak_ptr<Tab>` instead. `TerminalPage` is a WinRT type which supports `winrt::weak_ref<TerminalPage>`. All previous instance of `TerminalPage` lambdas capturing `this` has been replaced to capture `winrt::weak_ref<TerminalPage>`. These weak pointers/references can only be created after object construction necessitating for `Tab` a new function called after construction to bind lambdas. Any anomalous crash related to the following functionality during closing a tab or WT may be fixed by this PR: - Tab icon updating - Tab text updating - Tab dragging - Clicking new tab button - Changing active pane - Closing an active tab - Clicking on a tab - Creating the new tab flyout menu Sorry about all the commits. Will fix my fork after this PR! 😅 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Attempted to repro the steps indicated in issue #3776 with the new changes and failed. When before the changes, the issue could consistently be reproed.
2019-12-06 00:18:22 +01:00
if (auto page{ weakThis.get() })
{
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
page->_OpenNewTerminal(NewTerminalArgs());
}
});
_newTabButton.Drop([weakThis{ get_weak() }](Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::DragEventArgs e) {
if (auto page{ weakThis.get() })
{
page->NewTerminalByDrop(e);
Fixed self reference capture in Tab and TerminalPage (#3835) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Every lambda capture in `Tab` and `TerminalPage` has been changed from capturing raw `this` to `std::weak_ptr<Tab>` or `winrt::weak_ref<TerminalPage>`. Lambda bodies have been changed to check the weak reference before use. Capturing raw `this` in `Tab`'s [title change event handler](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/Tab.cpp#L299) was the root cause of #3776, and is fixed in this PR among other instance of raw `this` capture. The lambda fixes to `TerminalPage` are unrelated to the core issue addressed in the PR checklist. Because I was already editing `TerminalPage`, figured I'd do a [weak_ref pass](https://github.com/microsoft/terminal/issues/3776#issuecomment-560575575). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3776, potentially #2248, likely closes others * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3776 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments `Tab` now inherits from `enable_shared_from_this`, which enable accessing `Tab` objects as `std::weak_ptr<Tab>` objects. All instances of lambdas capturing `this` now capture `std::weak_ptr<Tab>` instead. `TerminalPage` is a WinRT type which supports `winrt::weak_ref<TerminalPage>`. All previous instance of `TerminalPage` lambdas capturing `this` has been replaced to capture `winrt::weak_ref<TerminalPage>`. These weak pointers/references can only be created after object construction necessitating for `Tab` a new function called after construction to bind lambdas. Any anomalous crash related to the following functionality during closing a tab or WT may be fixed by this PR: - Tab icon updating - Tab text updating - Tab dragging - Clicking new tab button - Changing active pane - Closing an active tab - Clicking on a tab - Creating the new tab flyout menu Sorry about all the commits. Will fix my fork after this PR! 😅 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Attempted to repro the steps indicated in issue #3776 with the new changes and failed. When before the changes, the issue could consistently be reproed.
2019-12-06 00:18:22 +01:00
}
});
_tabView.SelectionChanged({ this, &TerminalPage::_OnTabSelectionChanged });
_tabView.TabCloseRequested({ this, &TerminalPage::_OnTabCloseRequested });
_tabView.TabItemsChanged({ this, &TerminalPage::_OnTabItemsChanged });
_CreateNewTabFlyout();
_UpdateTabWidthMode();
_tabContent.SizeChanged({ this, &TerminalPage::_OnContentSizeChanged });
// When the visibility of the command palette changes to "collapsed",
// the palette has been closed. Toss focus back to the currently active
// control.
CommandPalette().RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) {
if (CommandPalette().Visibility() == Visibility::Collapsed)
{
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
_FocusActiveControl(nullptr, nullptr);
}
});
CommandPalette().DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested });
CommandPalette().CommandLineExecutionRequested({ this, &TerminalPage::_OnCommandLineExecutionRequested });
CommandPalette().SwitchToTabRequested({ this, &TerminalPage::_OnSwitchToTabRequested });
Enable previewing the color scheme in the command palette (#9794) ## Summary of the Pull Request Allow schemes to be previewed as the user hovers over them in the Command Palette. ![preview-set-color-scheme](https://user-images.githubusercontent.com/18356694/114557761-9a3cbd80-9c2f-11eb-987f-eb0c89ee1fa6.gif) ## References * Branched off of #8392, which is why the commit history is so polluted. 330a8e8 : 544b2fd has the interesting commits * #5400: cmdpal megathread ### Potential follow-ups * changing the font size * changing the font face * changing the opacity of acrylic ## PR Checklist * [x] Closes #6689, a last straggling FHL PR * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated - I don't think so ## Detailed Description of the Pull Request / Additional comments This works by inserting a "preview" `TerminalSettings` into the settings hierarchy, before the `TermControl`'s runtime settings, and after the ones from the actual `CascadiaSettings`. This allows us to modify that preview settings object, then discard it when we're done with the preview. This could also be used for other settings in the future - I built it to be extensible to other `ShortcutAction`s, though I haven't implemented those yet. ## Validation Steps Performed * Select a colorscheme - it becomes the active one * `colortool -x <scheme>` after selecting a scheme - colortool overrides the selected scheme * Select a colorscheme after a `colortool -x <scheme>` after selecting a scheme - the scheme in the palette becomes the active one * Pressing <kbd>esc</kbd> at any point to dismiss the command palette - scheme returns to the previous one * reloading the settings - returns to the scheme in the settings
2021-04-21 22:35:06 +02:00
CommandPalette().PreviewAction({ this, &TerminalPage::_PreviewActionHandler });
// Settings AllowDependentAnimations will affect whether animations are
// enabled application-wide, so we don't need to check it each time we
// want to create an animation.
WUX::Media::Animation::Timeline::AllowDependentAnimations(!_settings.GlobalSettings().DisableAnimations());
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
// Once the page is actually laid out on the screen, trigger all our
// startup actions. Things like Panes need to know at least how big the
// window will be, so they can subdivide that space.
//
// _OnFirstLayout will remove this handler so it doesn't get called more than once.
_layoutUpdatedRevoker = _tabContent.LayoutUpdated(winrt::auto_revoke, { this, &TerminalPage::_OnFirstLayout });
7996: Always on Top setting does not persist (#8125) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/issues/7996 * [x] CLA signed. * [ ] Documentation updated - irrelevant * [ ] Schema updated - irrelevant * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Currently the value of AlwaysOnTop is read by the AppHost from AppLogic that takes this value from the root TerminalPage. However at this stage neither AppLogic nor TerminalPage are initialized, and thus the return value is always false. This PR introduces a "GetInitialAlwaysOnTop" method to AppLogic that returns a value that is configured in the settings. In addition, the TerminalPage creation was fixed to read the configuration value upon creation (and not just after settings reload). <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed * Only manual testing * Starting the system with both initial value set to true and false * Verifying that dynamic toggling on / off is not affected
2020-11-02 19:51:29 +01:00
_isAlwaysOnTop = _settings.GlobalSettings().AlwaysOnTop();
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
// DON'T set up Toasts/TeachingTips here. They should be loaded and
// initialized the first time they're opened, in whatever method opens
// them.
// Setup mouse vanish attributes
SystemParametersInfoW(SPI_GETMOUSEVANISH, 0, &_shouldMouseVanish, false);
_tabRow.ShowElevationShield(IsElevated() && _settings.GlobalSettings().ShowAdminShield());
// Store cursor, so we can restore it, e.g., after mouse vanishing
// (we'll need to adapt this logic once we make cursor context aware)
try
{
_defaultPointerCursor = CoreWindow::GetForCurrentThread().PointerCursor();
}
CATCH_LOG();
ShowSetAsDefaultInfoBar();
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
}
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
// Method Description;
// - Checks if the current terminal window should load or save its layout information.
// Arguments:
// - settings: The settings to use as this may be called before the page is
// fully initialized.
// Return Value:
// - true if the ApplicationState should be used.
bool TerminalPage::ShouldUsePersistedLayout(CascadiaSettings& settings) const
{
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
// GH#5000 Until there is a separate state file for elevated sessions we should just not
// save at all while in an elevated window.
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
return Feature_PersistedWindowLayout::IsEnabled() &&
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
!IsElevated() &&
settings.GlobalSettings().FirstWindowPreference() == FirstWindowPreference::PersistedWindowLayout;
}
// Method Description;
// - Checks if the current window is configured to load a particular layout
// Arguments:
// - settings: The settings to use as this may be called before the page is
// fully initialized.
// Return Value:
// - non-null if there is a particular saved layout to use
std::optional<uint32_t> TerminalPage::LoadPersistedLayoutIdx(CascadiaSettings& settings) const
{
return ShouldUsePersistedLayout(settings) ? _loadFromPersistedLayoutIdx : std::nullopt;
}
WindowLayout TerminalPage::LoadPersistedLayout(CascadiaSettings& settings) const
{
if (const auto idx = LoadPersistedLayoutIdx(settings))
{
const auto i = idx.value();
const auto layouts = ApplicationState::SharedInstance().PersistedWindowLayouts();
if (layouts && layouts.Size() > i)
{
return layouts.GetAt(i);
}
}
return nullptr;
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
}
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
winrt::fire_and_forget TerminalPage::NewTerminalByDrop(winrt::Windows::UI::Xaml::DragEventArgs& e)
{
Windows::Foundation::Collections::IVectorView<Windows::Storage::IStorageItem> items;
try
{
items = co_await e.DataView().GetStorageItemsAsync();
}
CATCH_LOG();
if (items.Size() == 1)
{
std::filesystem::path path(items.GetAt(0).Path().c_str());
if (!std::filesystem::is_directory(path))
{
path = path.parent_path();
}
NewTerminalArgs args;
args.StartingDirectory(winrt::hstring{ path.wstring() });
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
this->_OpenNewTerminal(args);
TraceLoggingWrite(
g_hTerminalAppProvider,
"NewTabByDragDrop",
TraceLoggingDescription("Event emitted when the user drag&drops onto the new tab button"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
}
}
// Method Description:
// - This method is called once command palette action was chosen for dispatching
// We'll use this event to dispatch this command.
// Arguments:
// - command - command to dispatch
// Return Value:
// - <none>
void TerminalPage::_OnDispatchCommandRequested(const IInspectable& /*sender*/, const Microsoft::Terminal::Settings::Model::Command& command)
{
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
const auto& actionAndArgs = command.ActionAndArgs();
_actionDispatch->DoAction(actionAndArgs);
}
// Method Description:
// - This method is called once command palette command line was chosen for execution
// We'll use this event to create a command line execution command and dispatch it.
// Arguments:
// - command - command to dispatch
// Return Value:
// - <none>
void TerminalPage::_OnCommandLineExecutionRequested(const IInspectable& /*sender*/, const winrt::hstring& commandLine)
{
ExecuteCommandlineArgs args{ commandLine };
ActionAndArgs actionAndArgs{ ShortcutAction::ExecuteCommandline, args };
_actionDispatch->DoAction(actionAndArgs);
}
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
// Method Description:
// - This method is called once on startup, on the first LayoutUpdated event.
// We'll use this event to know that we have an ActualWidth and
// ActualHeight, so we can now attempt to process our list of startup
// actions.
// - We'll remove this event handler when the event is first handled.
// - If there are no startup actions, we'll open a single tab with the
// default profile.
// Arguments:
// - <unused>
// Return Value:
// - <none>
void TerminalPage::_OnFirstLayout(const IInspectable& /*sender*/, const IInspectable& /*eventArgs*/)
{
// Only let this succeed once.
_layoutUpdatedRevoker.revoke();
// This event fires every time the layout changes, but it is always the
// last one to fire in any layout change chain. That gives us great
// flexibility in finding the right point at which to initialize our
// renderer (and our terminal). Any earlier than the last layout update
// and we may not know the terminal's starting size.
if (_startupState == StartupState::NotInitialized)
{
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
_startupState = StartupState::InStartup;
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
// If we are provided with an index, the cases where we have
// commandline args and startup actions are already handled.
if (const auto layout = LoadPersistedLayout(_settings))
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
{
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
if (layout.TabLayout().Size() > 0)
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
{
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
_startupActions = layout.TabLayout();
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
}
}
ProcessStartupActions(_startupActions, true);
// If we were told that the COM server needs to be started to listen for incoming
// default application connections, start it now.
// This MUST be done after we've registered the event listener for the new connections
// or the COM server might start receiving requests on another thread and dispatch
// them to nowhere.
_StartInboundListener();
}
}
// Routine Description:
// - Will start the listener for inbound console handoffs if we have already determined
// that we should do so.
// NOTE: Must be after TerminalPage::_OnNewConnection has been connected up.
// Arguments:
// - <unused> - Looks at _shouldStartInboundListener
// Return Value:
// - <none> - May fail fast if setup fails as that would leave us in a weird state.
void TerminalPage::_StartInboundListener()
{
if (_shouldStartInboundListener)
{
_shouldStartInboundListener = false;
try
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
{
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::StartInboundListener();
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
}
// If we failed to start the listener, it will throw.
// We don't want to fail fast here because if a peasant has some trouble with
// starting the listener, we don't want it to crash and take all its tabs down
// with it.
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
}
}
// Method Description:
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
// - Process all the startup actions in the provided list of startup
// actions. We'll do this all at once here.
// Arguments:
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
// - actions: a winrt vector of actions to process. Note that this must NOT
// be an IVector&, because we need the collection to be accessible on the
// other side of the co_await.
// - initial: if true, we're parsing these args during startup, and we
// should fire an Initialized event.
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
// - cwd: If not empty, we should try switching to this provided directory
// while processing these actions. This will allow something like `wt -w 0
// nt -d .` from inside another directory to work as expected.
// Return Value:
// - <none>
Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
winrt::fire_and_forget TerminalPage::ProcessStartupActions(Windows::Foundation::Collections::IVector<ActionAndArgs> actions,
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
const bool initial,
const winrt::hstring cwd)
{
auto weakThis{ get_weak() };
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
// Handle it on a subsequent pass of the UI thread.
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
// If the caller provided a CWD, switch to that directory, then switch
// back once we're done. This looks weird though, because we have to set
// up the scope_exit _first_. We'll release the scope_exit if we don't
// actually need it.
std::wstring originalCwd{ wil::GetCurrentDirectoryW<std::wstring>() };
auto restoreCwd = wil::scope_exit([&originalCwd]() {
// ignore errors, we'll just power on through. We'd rather do
// something rather than fail silently if the directory doesn't
// actually exist.
LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(originalCwd.c_str()));
});
if (cwd.empty())
{
restoreCwd.release();
}
else
{
// ignore errors, we'll just power on through. We'd rather do
// something rather than fail silently if the directory doesn't
// actually exist.
LOG_IF_WIN32_BOOL_FALSE(SetCurrentDirectory(cwd.c_str()));
}
if (auto page{ weakThis.get() })
{
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
for (const auto& action : actions)
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
{
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
if (auto page{ weakThis.get() })
{
_actionDispatch->DoAction(action);
}
else
{
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
co_return;
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
}
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
}
Only focus the active pane once initialization is complete (#10978) ## Summary of the Pull Request Since the days immemorial of the Terminal, the TermControl has auto-focused itself when it finalizes its layout. This has led to the problem that `wt ; sp ; sp ; sp...` ends up focusing one of these panes at random. This PR fixes this issue by getting rid of the auto-focusing. Panes now manually get focused when created. We manually focus the active pane when a commandline is dispatched. since we're internally tracking "active" separate from "focused", this ends up working as you'd hope. ## References ## PR Checklist * [x] Closes #6586 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I also had to turn the cursor off by default. Most `TermControl`s would never get the `LostFocus` event, so their cursors would get left `On`, and that's not right. ## Validation Steps Performed I've run the following things a bunch of times to make sure they work: * `wtd sp ; sp ; sp` * `wtd sp ; sp ; sp ; fp -t 0` * `newTab` * `splitPane` * use the command palette to do the above as well Where the result used to be random (cases 1 & 2), the result is exactly what you'd expect now. It doesn't work at all for ``` wtd sp ; sp ; sp ; mf left ``` Presumably because we can't `move-focus` directionally during startup. However, that doesn't work _today_ either, so it's not making it worse. Just highlights that single scenario doesn't work right.
2021-08-24 11:49:45 +02:00
// GH#6586: now that we're done processing all startup commands,
// focus the active control. This will work as expected for both
// commandline invocations and for `wt` action invocations.
if (const auto control = _GetActiveControl())
{
control.Focus(FocusState::Programmatic);
}
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
}
if (initial)
{
_CompleteInitialization();
}
}
// Method Description:
// - Perform and steps that need to be done once our initial state is all
// set up. This includes entering fullscreen mode and firing our
// Initialized event.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_CompleteInitialization()
{
_startupState = StartupState::Initialized;
_InitializedHandlers(*this, nullptr);
}
// Method Description:
// - Show a dialog with "About" information. Displays the app's Display
// Name, version, getting started link, documentation link, release
// Notes link, and privacy policy link.
void TerminalPage::_ShowAboutDialog()
{
if (auto presenter{ _dialogPresenter.get() })
{
presenter.ShowDialog(FindName(L"AboutDialog").try_as<WUX::Controls::ContentDialog>());
}
}
winrt::hstring TerminalPage::ApplicationDisplayName()
{
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
return CascadiaSettings::ApplicationDisplayName();
}
winrt::hstring TerminalPage::ApplicationVersion()
{
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
return CascadiaSettings::ApplicationVersion();
}
void TerminalPage::_ThirdPartyNoticesOnClick(const IInspectable& /*sender*/, const Windows::UI::Xaml::RoutedEventArgs& /*eventArgs*/)
{
std::filesystem::path currentPath{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
currentPath.replace_filename(L"NOTICE.html");
ShellExecute(nullptr, nullptr, currentPath.c_str(), nullptr, nullptr, SW_SHOW);
}
// Method Description:
// - Displays a dialog to warn the user that they are about to close all open windows.
// Once the user clicks the OK button, shut down the application.
// If cancel is clicked, the dialog will close.
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens. See _ShowDialog for details
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowQuitDialog()
{
if (auto presenter{ _dialogPresenter.get() })
{
co_return co_await presenter.ShowDialog(FindName(L"QuitDialog").try_as<WUX::Controls::ContentDialog>());
}
co_return ContentDialogResult::None;
}
// Method Description:
// - Displays a dialog for warnings found while closing the terminal app using
// key binding with multiple tabs opened. Display messages to warn user
// that more than 1 tab is opened, and once the user clicks the OK button, remove
// all the tabs and shut down and app. If cancel is clicked, the dialog will close
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens. See _ShowDialog for details
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowCloseWarningDialog()
{
if (auto presenter{ _dialogPresenter.get() })
{
co_return co_await presenter.ShowDialog(FindName(L"CloseAllDialog").try_as<WUX::Controls::ContentDialog>());
}
co_return ContentDialogResult::None;
}
// Method Description:
// - Displays a dialog for warnings found while closing the terminal tab marked as read-only
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowCloseReadOnlyDialog()
{
if (auto presenter{ _dialogPresenter.get() })
{
co_return co_await presenter.ShowDialog(FindName(L"CloseReadOnlyDialog").try_as<WUX::Controls::ContentDialog>());
}
co_return ContentDialogResult::None;
}
// Method Description:
// - Displays a dialog to warn the user about the fact that the text that
// they are trying to paste contains the "new line" character which can
// have the effect of starting commands without the user's knowledge if
// it is pasted on a shell where the "new line" character marks the end
// of a command.
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens. See _ShowDialog for details
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowMultiLinePasteWarningDialog()
{
if (auto presenter{ _dialogPresenter.get() })
{
co_return co_await presenter.ShowDialog(FindName(L"MultiLinePasteDialog").try_as<WUX::Controls::ContentDialog>());
}
co_return ContentDialogResult::None;
}
// Method Description:
// - Displays a dialog to warn the user about the fact that the text that
// they are trying to paste is very long, in case they did not mean to
// paste it but pressed the paste shortcut by accident.
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens. See _ShowDialog for details
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowLargePasteWarningDialog()
{
if (auto presenter{ _dialogPresenter.get() })
{
co_return co_await presenter.ShowDialog(FindName(L"LargePasteDialog").try_as<WUX::Controls::ContentDialog>());
}
co_return ContentDialogResult::None;
}
// Method Description:
// - Builds the flyout (dropdown) attached to the new tab button, and
// attaches it to the button. Populates the flyout with one entry per
// Profile, displaying the profile's name. Clicking each flyout item will
// open a new tab with that profile.
// Below the profiles are the static menu items: settings, command palette
void TerminalPage::_CreateNewTabFlyout()
{
auto newTabFlyout = WUX::Controls::MenuFlyout{};
newTabFlyout.Placement(WUX::Controls::Primitives::FlyoutPlacementMode::BottomEdgeAlignedLeft);
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
auto actionMap = _settings.ActionMap();
const auto defaultProfileGuid = _settings.GlobalSettings().DefaultProfile();
// the number of profiles should not change in the loop for this to work
auto const profileCount = gsl::narrow_cast<int>(_settings.ActiveProfiles().Size());
for (int profileIndex = 0; profileIndex < profileCount; profileIndex++)
{
const auto profile = _settings.ActiveProfiles().GetAt(profileIndex);
auto profileMenuItem = WUX::Controls::MenuFlyoutItem{};
// Add the keyboard shortcuts based on the number of profiles defined
// Look for a keychord that is bound to the equivalent
// NewTab(ProfileIndex=N) action
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
NewTerminalArgs newTerminalArgs{ profileIndex };
NewTabArgs newTabArgs{ newTerminalArgs };
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
auto profileKeyChord{ actionMap.GetKeyBindingForAction(ShortcutAction::NewTab, newTabArgs) };
// make sure we find one to display
if (profileKeyChord)
{
_SetAcceleratorForMenuItem(profileMenuItem, profileKeyChord);
}
auto profileName = profile.Name();
profileMenuItem.Text(profileName);
// If there's an icon set for this profile, set it as the icon for
// this flyout item.
if (!profile.Icon().empty())
{
const auto iconSource{ IconPathConverter().IconSourceWUX(profile.Icon()) };
WUX::Controls::IconSourceElement iconElement;
iconElement.IconSource(iconSource);
profileMenuItem.Icon(iconElement);
Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
}
if (profile.Guid() == defaultProfileGuid)
{
// Contrast the default profile with others in font weight.
profileMenuItem.FontWeight(FontWeights::Bold());
}
auto newTabRun = WUX::Documents::Run();
newTabRun.Text(RS_(L"NewTabRun/Text"));
auto newPaneRun = WUX::Documents::Run();
newPaneRun.Text(RS_(L"NewPaneRun/Text"));
newPaneRun.FontStyle(FontStyle::Italic);
auto newWindowRun = WUX::Documents::Run();
newWindowRun.Text(RS_(L"NewWindowRun/Text"));
newWindowRun.FontStyle(FontStyle::Italic);
auto textBlock = WUX::Controls::TextBlock{};
textBlock.Inlines().Append(newTabRun);
textBlock.Inlines().Append(WUX::Documents::LineBreak{});
textBlock.Inlines().Append(newPaneRun);
textBlock.Inlines().Append(WUX::Documents::LineBreak{});
textBlock.Inlines().Append(newWindowRun);
auto toolTip = WUX::Controls::ToolTip{};
toolTip.Content(textBlock);
WUX::Controls::ToolTipService::SetToolTip(profileMenuItem, toolTip);
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
profileMenuItem.Click([profileIndex, weakThis{ get_weak() }](auto&&, auto&&) {
Fixed self reference capture in Tab and TerminalPage (#3835) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Every lambda capture in `Tab` and `TerminalPage` has been changed from capturing raw `this` to `std::weak_ptr<Tab>` or `winrt::weak_ref<TerminalPage>`. Lambda bodies have been changed to check the weak reference before use. Capturing raw `this` in `Tab`'s [title change event handler](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/Tab.cpp#L299) was the root cause of #3776, and is fixed in this PR among other instance of raw `this` capture. The lambda fixes to `TerminalPage` are unrelated to the core issue addressed in the PR checklist. Because I was already editing `TerminalPage`, figured I'd do a [weak_ref pass](https://github.com/microsoft/terminal/issues/3776#issuecomment-560575575). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3776, potentially #2248, likely closes others * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3776 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments `Tab` now inherits from `enable_shared_from_this`, which enable accessing `Tab` objects as `std::weak_ptr<Tab>` objects. All instances of lambdas capturing `this` now capture `std::weak_ptr<Tab>` instead. `TerminalPage` is a WinRT type which supports `winrt::weak_ref<TerminalPage>`. All previous instance of `TerminalPage` lambdas capturing `this` has been replaced to capture `winrt::weak_ref<TerminalPage>`. These weak pointers/references can only be created after object construction necessitating for `Tab` a new function called after construction to bind lambdas. Any anomalous crash related to the following functionality during closing a tab or WT may be fixed by this PR: - Tab icon updating - Tab text updating - Tab dragging - Clicking new tab button - Changing active pane - Closing an active tab - Clicking on a tab - Creating the new tab flyout menu Sorry about all the commits. Will fix my fork after this PR! 😅 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Attempted to repro the steps indicated in issue #3776 with the new changes and failed. When before the changes, the issue could consistently be reproed.
2019-12-06 00:18:22 +01:00
if (auto page{ weakThis.get() })
{
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
NewTerminalArgs newTerminalArgs{ profileIndex };
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
page->_OpenNewTerminal(newTerminalArgs);
Fixed self reference capture in Tab and TerminalPage (#3835) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Every lambda capture in `Tab` and `TerminalPage` has been changed from capturing raw `this` to `std::weak_ptr<Tab>` or `winrt::weak_ref<TerminalPage>`. Lambda bodies have been changed to check the weak reference before use. Capturing raw `this` in `Tab`'s [title change event handler](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/Tab.cpp#L299) was the root cause of #3776, and is fixed in this PR among other instance of raw `this` capture. The lambda fixes to `TerminalPage` are unrelated to the core issue addressed in the PR checklist. Because I was already editing `TerminalPage`, figured I'd do a [weak_ref pass](https://github.com/microsoft/terminal/issues/3776#issuecomment-560575575). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3776, potentially #2248, likely closes others * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3776 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments `Tab` now inherits from `enable_shared_from_this`, which enable accessing `Tab` objects as `std::weak_ptr<Tab>` objects. All instances of lambdas capturing `this` now capture `std::weak_ptr<Tab>` instead. `TerminalPage` is a WinRT type which supports `winrt::weak_ref<TerminalPage>`. All previous instance of `TerminalPage` lambdas capturing `this` has been replaced to capture `winrt::weak_ref<TerminalPage>`. These weak pointers/references can only be created after object construction necessitating for `Tab` a new function called after construction to bind lambdas. Any anomalous crash related to the following functionality during closing a tab or WT may be fixed by this PR: - Tab icon updating - Tab text updating - Tab dragging - Clicking new tab button - Changing active pane - Closing an active tab - Clicking on a tab - Creating the new tab flyout menu Sorry about all the commits. Will fix my fork after this PR! 😅 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Attempted to repro the steps indicated in issue #3776 with the new changes and failed. When before the changes, the issue could consistently be reproed.
2019-12-06 00:18:22 +01:00
}
});
newTabFlyout.Items().Append(profileMenuItem);
}
// add menu separator
auto separatorItem = WUX::Controls::MenuFlyoutSeparator{};
newTabFlyout.Items().Append(separatorItem);
// add static items
{
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
// GH#2455 - Make sure to try/catch calls to Application::Current,
// because that _won't_ be an instance of TerminalApp::App in the
// LocalTests
auto isUwp = false;
try
{
isUwp = ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Logic().IsUwp();
}
CATCH_LOG();
if (!isUwp)
{
// Create the settings button.
auto settingsItem = WUX::Controls::MenuFlyoutItem{};
settingsItem.Text(RS_(L"SettingsMenuItem"));
WUX::Controls::SymbolIcon ico{};
ico.Symbol(WUX::Controls::Symbol::Setting);
settingsItem.Icon(ico);
settingsItem.Click({ this, &TerminalPage::_SettingsButtonOnClick });
newTabFlyout.Items().Append(settingsItem);
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
const auto settingsKeyChord{ actionMap.GetKeyBindingForAction(ShortcutAction::OpenSettings, OpenSettingsArgs{ SettingsTarget::SettingsUI }) };
if (settingsKeyChord)
{
_SetAcceleratorForMenuItem(settingsItem, settingsKeyChord);
}
// Create the command palette button.
auto commandPaletteFlyout = WUX::Controls::MenuFlyoutItem{};
commandPaletteFlyout.Text(RS_(L"CommandPaletteMenuItem"));
WUX::Controls::FontIcon commandPaletteIcon{};
commandPaletteIcon.Glyph(L"\xE945");
commandPaletteIcon.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
commandPaletteFlyout.Icon(commandPaletteIcon);
commandPaletteFlyout.Click({ this, &TerminalPage::_CommandPaletteButtonOnClick });
newTabFlyout.Items().Append(commandPaletteFlyout);
const auto commandPaletteKeyChord{ actionMap.GetKeyBindingForAction(ShortcutAction::ToggleCommandPalette) };
if (commandPaletteKeyChord)
{
_SetAcceleratorForMenuItem(commandPaletteFlyout, commandPaletteKeyChord);
}
}
// Create the about button.
auto aboutFlyout = WUX::Controls::MenuFlyoutItem{};
Introduce a WinRT utils library and "checked resources" (#3350) This commit introduces a C++/WinRT utility library and moves ScopedResourceLoader into it. I decided to get uppity and introduce something I like to call "checked resources." The idea is that every resource reference from a library is knowable at compile time, and we should be able to statically ensure that all resources exist. This is a system that lets us immediately failfast (on launch) when a library makes a static reference to a resource that doesn't exist at runtime. It exposes two new (preprocessor) APIs: * `RS_(wchar_t)`: loads a localizable string resource by name. * `USES_RESOURCE(wchar_t)`: marks a resource key as used, but is intended for loading images or passing static resource keys as parameters to functions that will look them up later. Resource checking relies on diligent use of `USES_RESOURCE()` and `RS_()` (which uses `USES_RESOURCE`), but can make sure we don't ship something that'll blow up at runtime. It works like this: **IN DEBUG MODE** - All resource names referenced through `USES_RESOURCE()` are emitted alongside their referencing filenames and line numbers into a static section of the binary. That section is named `.util$res$m`. - We emit two sentinel values into two different sections, `.util$res$a` and `.util$res$z`. - The linker sorts all sections alphabetically before crushing them together into the final binary. - When we first construct a library's scoped resource loader, we iterate over every resource reference between `$a` and `$z` and check residency. **IN RELEASE MODE** - All checked resource code is compiled out. Fixes #2146. Macros are the only way to do something this cool, incidentally. ## Validation Steps Performed Made references to a bunch of bad resources, tried to break it a lot. It looks like this when it fails: ### App.cpp ``` 36 static const std::array<std::wstring_view, 2> settingsLoadErrorsLabels { 37 USES_RESOURCE(L"NoProfilesText"), 38 USES_RESOURCE(L"AllProfilesHiddenText_HA_JUST_KIDDING") 39 }; ``` ``` WinRTUtils\LibraryResources.cpp(68)\TerminalApp.dll: FailFast(1) tid(1034) 8000FFFF Catastrophic failure Msg:[Resource AllProfilesHiddenText_HA_JUST_KIDDING not found in scope TerminalApp/Resources (App.cpp:38)] [EnsureAllResourcesArePresent] ```
2019-11-01 23:47:05 +01:00
aboutFlyout.Text(RS_(L"AboutMenuItem"));
WUX::Controls::SymbolIcon aboutIcon{};
aboutIcon.Symbol(WUX::Controls::Symbol::Help);
aboutFlyout.Icon(aboutIcon);
aboutFlyout.Click({ this, &TerminalPage::_AboutButtonOnClick });
newTabFlyout.Items().Append(aboutFlyout);
}
// Before opening the fly-out set focus on the current tab
// so no matter how fly-out is closed later on the focus will return to some tab.
// We cannot do it on closing because if the window loses focus (alt+tab)
// the closing event is not fired.
// It is important to set the focus on the tab
// Since the previous focus location might be discarded in the background,
// e.g., the command palette will be dismissed by the menu,
// and then closing the fly-out will move the focus to wrong location.
newTabFlyout.Opening([this](auto&&, auto&&) {
minor refactor: Move Tab management into its own file (#9629) I think we can all agree that `TerminalPage.cpp` is an unruly beast of a file. It's got everything. It does everything. It can sometimes be a bit hard to work with, because of simply how big it is. This PR tries to alleviate this by making `TerminalPage.cpp` just a little smaller. It does so by moving pretty much everything related to tab management into its own file, `TabManagement.cpp`. These methods that have moved are all the same as they were before, and they're still members of `TerminalPage`. But now they're all in one place. I tried to move all the references to `_tabs` in `TerminalPage.cpp`, but there's still a few that I left behind. Mostly because I felt that moving those would be too gnarly a code change for an otherwise simple cut&paste PR. There are a few new methods I introduced: * `_TabDragStarted` and `_TabDragCompleted`: These were lambdas before, promoted to full methods. * `_DismissTabContextMenus`: Remove all the right-click context menus from the tabs * `_FocusCurrentTab`: This one's a bit trickier, we were actually doing this in a few different places, so I tried consolidating. * `_HasMultipleTabs`: This doesn't need explaining. * `_RemoveAllTabs`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` * `_ResizeTabContent`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` In the future, some enterprising young soul could try promoting that file to its own class, and hiding `_tabs` (and `_mruTabs`) inside it. Probably would need to take a reference to TerminalPage's `_tabView` and `_newTabButton`. I'm not doing that right now, because I already hate the idea of the ... > 920 additions and 847 deletions. ... I'm making you look at already. ## Other thoughts Some of the calls might be a little arbitrary - `_OpenNewTab` and `_CreateNewTabFromSettings` probably should stay in `TerminalPage`? Or at least elements of those might need to get split up better. Similarly `TerminalPage::_OpenSettingsUI` stayed in `TerminalPage.cpp`, but it does a lot of the same work as `_CreateNewTabFromSettings`. I'm not saying this is the definitive places for these methods - it's code we're working with, not stone ☺️
2021-03-29 21:53:39 +02:00
_FocusCurrentTab(true);
});
_newTabButton.Flyout(newTabFlyout);
}
// Function Description:
// Called when the openNewTabDropdown keybinding is used.
// Shows the dropdown flyout.
void TerminalPage::_OpenNewTabDropdown()
{
_newTabButton.Flyout().ShowAt(_newTabButton);
}
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
void TerminalPage::_OpenNewTerminal(const NewTerminalArgs newTerminalArgs)
{
// if alt is pressed, open a pane
const CoreWindow window = CoreWindow::GetForCurrentThread();
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
const bool altPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) ||
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
const auto shiftState{ window.GetKeyState(VirtualKey::Shift) };
const auto rShiftState = window.GetKeyState(VirtualKey::RightShift);
const auto lShiftState = window.GetKeyState(VirtualKey::LeftShift);
const auto shiftPressed{ WI_IsFlagSet(shiftState, CoreVirtualKeyStates::Down) ||
WI_IsFlagSet(lShiftState, CoreVirtualKeyStates::Down) ||
WI_IsFlagSet(rShiftState, CoreVirtualKeyStates::Down) };
// Check for DebugTap
bool debugTap = this->_settings.GlobalSettings().DebugFeaturesEnabled() &&
WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
if (altPressed && !debugTap)
{
Add the ability to split a pane and put the new pane first. (#11145) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds directional modifiers for SplitState and convert those to the appropriate horizontal/vertical when splitting a pane. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #4340 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments "vertical" and "horizontal" splits were removed from `defaults.json`, but code was added to parse those as `right` and `down` respectively. It is also the case that if a user has a custom hotkey for `split: vertical` it will override the default for `split: right`. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Split the pane using each of the new directional movements
2021-09-15 22:14:57 +02:00
this->_SplitPane(SplitDirection::Automatic,
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
SplitType::Manual,
0.5f,
newTerminalArgs);
}
else if (shiftPressed && !debugTap)
{
// Manually fill in the evaluated profile.
if (newTerminalArgs.ProfileIndex() != nullptr)
{
// We want to promote the index to a GUID because there is no "launch to profile index" command.
const auto profile = _settings.GetProfileForArgs(newTerminalArgs);
if (profile)
{
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
}
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
}
this->_OpenNewWindow(false, newTerminalArgs);
}
else
{
LOG_IF_FAILED(this->_OpenNewTab(newTerminalArgs));
implement drag&drop path in '+' button (#10073) (#10160) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR implements the ability to drop directories/files on the '+' button which in turn will open the tab/pane/window in the given starting path. In order to do this, I refactored the click's lambda into a method and re-used it Sadly I wasn't able to add note about the alt/shift feature (any ideas how to do this?) Also most of the code is "look-a-like" from other places within the project, as I don't have much experience in windows development. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References implements #10073 ## PR Checklist * [ ] Closes #10073 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed ** tests were done manually both of the old feature (alt/shift+click) on the '+' and on the profiles * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx ** no idea what to add there, if any. * [ ] Schema updated. * [ ] 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 ## Validation Steps Performed tested manually.
2021-07-20 16:26:35 +02:00
}
}
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
winrt::fire_and_forget TerminalPage::_RemoveOnCloseRoutine(Microsoft::UI::Xaml::Controls::TabViewItem tabViewItem, winrt::com_ptr<TerminalPage> page)
{
co_await winrt::resume_foreground(page->_tabView.Dispatcher());
if (auto tab{ _GetTabByTabViewItem(tabViewItem) })
{
_RemoveTab(tab);
}
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
}
// Method Description:
// - Creates a new connection based on the profile settings
// Arguments:
// - the profile we want the settings from
// - the terminal settings
// Return value:
// - the desired connection
TerminalConnection::ITerminalConnection TerminalPage::_CreateConnectionFromSettings(Profile profile,
TerminalSettings settings)
{
TerminalConnection::ITerminalConnection connection{ nullptr };
winrt::guid connectionType = profile.ConnectionType();
winrt::guid sessionGuid{};
if (connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
TerminalConnection::AzureConnection::IsAzureConnectionAvailable())
{
// TODO GH#4661: Replace this with directly using the AzCon when our VT is better
std::filesystem::path azBridgePath{ wil::GetModuleFileNameW<std::wstring>(nullptr) };
azBridgePath.replace_filename(L"TerminalAzBridge.exe");
Switch Connections to use `ValueSet`s to initialize them (#10184) #### ⚠️ targets #10051 ## Summary of the Pull Request This PR does one big, primary thing. It removes all the constructors from any TerminalConnections, and changes them to use an `Initialize` method that accepts a `ValueSet` of properties. Why? For the upcoming window/content process work, we'll need the content process to be able to initialize the connection _in the content process_. However, the window process will be the one that knows what type of connection to make. Enter `ConnectionInformation`. This class will let us specify the class name of the type we want to create, and a set of settings to use when initializing that connection. **IMPORTANT**: As a part of this, the constructor for a connection must have 0 arguments. `RoActivateInstance` lets you just conjure a WinRT type just by class name, but that class must have a 0 arg ctor. Hence the need for `Initialize`, to actually pass the settings. We're using a `ValueSet` here because it's basically a json blob, with more steps. In the future, when extension authors want to have custom connections, we can always deserialize the json into a `ValueSet`, pass it to their connection's `Initialize`, and let then get what they need out of it. ## References * Tear-out: #1256 * Megathread: #5000 * Project: https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760298 * [x] I work here * [n/a] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments `ConnectionInformation` was included as a part of this PR, to demonstrate how this will eventually be used. `ConnectionInformation` is not _currently_ used. ## Validation Steps Performed It still builds and runs.
2021-07-20 17:02:17 +02:00
connection = TerminalConnection::ConptyConnection();
connection.Initialize(TerminalConnection::ConptyConnection::CreateSettings(azBridgePath.wstring(),
L".",
L"Azure",
nullptr,
::base::saturated_cast<uint32_t>(settings.InitialRows()),
::base::saturated_cast<uint32_t>(settings.InitialCols()),
winrt::guid()));
}
else
{
// profile is guaranteed to exist here
std::wstring guidWString = Utils::GuidToString(profile.Guid());
StringMap envMap{};
envMap.Insert(L"WT_PROFILE_ID", guidWString);
envMap.Insert(L"WSLENV", L"WT_PROFILE_ID");
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
// Update the path to be relative to whatever our CWD is.
//
// Refer to the examples in
// https://en.cppreference.com/w/cpp/filesystem/path/append
//
// We need to do this here, to ensure we tell the ConptyConnection
// the correct starting path. If we're being invoked from another
// terminal instance (e.g. wt -w 0 -d .), then we have switched our
// CWD to the provided path. We should treat the StartingDirectory
// as relative to the current CWD.
//
// The connection must be informed of the current CWD on
// construction, because the connection might not spawn the child
// process until later, on another thread, after we've already
// restored the CWD to it's original value.
When launching wsl, promote the starting directory to --cd (#9223) This commit introduces a hack to ConptyConnection for launching WSL. When we detect that WSL is being launched (either "wsl" or "wsl.exe", unqialified or _specifically_ from the current OS's System32 directory), we will promote the startingDirectory specified at launch time into a commandline argument. Why do we want to switch to `--cd`? With the current design of ConptyConnection and WSL, there are some significant limitations: * `startingDirectory` cannot be a WSL path, which forces users to use weird tricks such as setting the starting directory to `\\wsl$\Distro\home\user`. * WSL occasionally fails to launch in time to handle a `\\wsl$` path, which makes us spawn in a strange location (or no location at all). (This fix will only address the second one until a WSL update is released that adds support for `--cd $LINUX_PATH`.) We will not do the promotion if any of the following are true: * the commandline contains `--cd` already * the commandline contains a bare `~` * This was a commonly-used workaround that forced wsl to start in the user's home directory. It conflicts with --cd. * wsl is not spelled properly (`WSL` and `WSL.EXE` are unacceptable) * an absolute path to wsl outside the system32 directory is provided We chose the do this trick in the connection layer, the latest possible point, because it captures the most use cases. We could have done it earlier, but the options were quite limiting. They are: * Generate WSL profiles with startingDirectory set to the home folder * We can't do this because we do not know the user's home folder path. * Generate WSL profiles with `--cd` in them. * This only works for unmodified profiles. * This only works for generated profiles. * Users cannot override the commandline without breaking it. * Users cannot specify a startingDirectory (!) since the one on the commandline wins. * Set a flag on generated WSL profiles to request this trick * This only works for generated profiles. Users who create their own WSL profiles couldn't set startingDirectory and have it work the same. Patching the commandline, hacky though it may be, seemed to be the most compatible option. Eventually, we can even support `wt -d ~ wsl`! ## Validation Steps Performed Manual validation for the following cases: ```c++ // MUST MANGLE auto a01 = _tryMangleStartingDirectoryForWSL(LR"(wsl)", L"SENTINEL"); auto a02 = _tryMangleStartingDirectoryForWSL(LR"(wsl -d X)", L"SENTINEL"); auto a03 = _tryMangleStartingDirectoryForWSL(LR"(wsl -d X ~/bin/sh)", L"SENTINEL"); auto a04 = _tryMangleStartingDirectoryForWSL(LR"(wsl.exe)", L"SENTINEL"); auto a05 = _tryMangleStartingDirectoryForWSL(LR"(wsl.exe -d X)", L"SENTINEL"); auto a06 = _tryMangleStartingDirectoryForWSL(LR"(wsl.exe -d X ~/bin/sh)", L"SENTINEL"); auto a07 = _tryMangleStartingDirectoryForWSL(LR"("wsl")", L"SENTINEL"); auto a08 = _tryMangleStartingDirectoryForWSL(LR"("wsl.exe")", L"SENTINEL"); auto a09 = _tryMangleStartingDirectoryForWSL(LR"("wsl" -d X)", L"SENTINEL"); auto a10 = _tryMangleStartingDirectoryForWSL(LR"("wsl.exe" -d X)", L"SENTINEL"); auto a11 = _tryMangleStartingDirectoryForWSL(LR"("C:\Windows\system32\wsl.exe" -d X)", L"SENTINEL"); auto a12 = _tryMangleStartingDirectoryForWSL(LR"("C:\windows\system32\wsl" -d X)", L"SENTINEL"); auto a13 = _tryMangleStartingDirectoryForWSL(LR"(wsl ~/bin)", L"SENTINEL"); // MUST NOT MANGLE auto a14 = _tryMangleStartingDirectoryForWSL(LR"("C:\wsl.exe" -d X)", L"SENTINEL"); auto a15 = _tryMangleStartingDirectoryForWSL(LR"(C:\wsl.exe)", L"SENTINEL"); auto a16 = _tryMangleStartingDirectoryForWSL(LR"(wsl --cd C:\)", L"SENTINEL"); auto a17 = _tryMangleStartingDirectoryForWSL(LR"(wsl ~)", L"SENTINEL"); auto a18 = _tryMangleStartingDirectoryForWSL(LR"(wsl ~ -d Ubuntu)", L"SENTINEL"); ``` We don't have anywhere to put TerminalConnection unit tests :| Closes #592.
2021-08-02 22:39:11 +02:00
winrt::hstring newWorkingDirectory{ settings.StartingDirectory() };
if (newWorkingDirectory.size() <= 1 ||
!(newWorkingDirectory[0] == L'~' || newWorkingDirectory[0] == L'/'))
{ // We only want to resolve the new WD against the CWD if it doesn't look like a Linux path (see GH#592)
std::wstring cwdString{ wil::GetCurrentDirectoryW<std::wstring>() };
std::filesystem::path cwd{ cwdString };
cwd /= settings.StartingDirectory().c_str();
newWorkingDirectory = winrt::hstring{ cwd.wstring() };
}
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
Switch Connections to use `ValueSet`s to initialize them (#10184) #### ⚠️ targets #10051 ## Summary of the Pull Request This PR does one big, primary thing. It removes all the constructors from any TerminalConnections, and changes them to use an `Initialize` method that accepts a `ValueSet` of properties. Why? For the upcoming window/content process work, we'll need the content process to be able to initialize the connection _in the content process_. However, the window process will be the one that knows what type of connection to make. Enter `ConnectionInformation`. This class will let us specify the class name of the type we want to create, and a set of settings to use when initializing that connection. **IMPORTANT**: As a part of this, the constructor for a connection must have 0 arguments. `RoActivateInstance` lets you just conjure a WinRT type just by class name, but that class must have a 0 arg ctor. Hence the need for `Initialize`, to actually pass the settings. We're using a `ValueSet` here because it's basically a json blob, with more steps. In the future, when extension authors want to have custom connections, we can always deserialize the json into a `ValueSet`, pass it to their connection's `Initialize`, and let then get what they need out of it. ## References * Tear-out: #1256 * Megathread: #5000 * Project: https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760298 * [x] I work here * [n/a] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments `ConnectionInformation` was included as a part of this PR, to demonstrate how this will eventually be used. `ConnectionInformation` is not _currently_ used. ## Validation Steps Performed It still builds and runs.
2021-07-20 17:02:17 +02:00
auto conhostConn = TerminalConnection::ConptyConnection();
conhostConn.Initialize(TerminalConnection::ConptyConnection::CreateSettings(settings.Commandline(),
When launching wsl, promote the starting directory to --cd (#9223) This commit introduces a hack to ConptyConnection for launching WSL. When we detect that WSL is being launched (either "wsl" or "wsl.exe", unqialified or _specifically_ from the current OS's System32 directory), we will promote the startingDirectory specified at launch time into a commandline argument. Why do we want to switch to `--cd`? With the current design of ConptyConnection and WSL, there are some significant limitations: * `startingDirectory` cannot be a WSL path, which forces users to use weird tricks such as setting the starting directory to `\\wsl$\Distro\home\user`. * WSL occasionally fails to launch in time to handle a `\\wsl$` path, which makes us spawn in a strange location (or no location at all). (This fix will only address the second one until a WSL update is released that adds support for `--cd $LINUX_PATH`.) We will not do the promotion if any of the following are true: * the commandline contains `--cd` already * the commandline contains a bare `~` * This was a commonly-used workaround that forced wsl to start in the user's home directory. It conflicts with --cd. * wsl is not spelled properly (`WSL` and `WSL.EXE` are unacceptable) * an absolute path to wsl outside the system32 directory is provided We chose the do this trick in the connection layer, the latest possible point, because it captures the most use cases. We could have done it earlier, but the options were quite limiting. They are: * Generate WSL profiles with startingDirectory set to the home folder * We can't do this because we do not know the user's home folder path. * Generate WSL profiles with `--cd` in them. * This only works for unmodified profiles. * This only works for generated profiles. * Users cannot override the commandline without breaking it. * Users cannot specify a startingDirectory (!) since the one on the commandline wins. * Set a flag on generated WSL profiles to request this trick * This only works for generated profiles. Users who create their own WSL profiles couldn't set startingDirectory and have it work the same. Patching the commandline, hacky though it may be, seemed to be the most compatible option. Eventually, we can even support `wt -d ~ wsl`! ## Validation Steps Performed Manual validation for the following cases: ```c++ // MUST MANGLE auto a01 = _tryMangleStartingDirectoryForWSL(LR"(wsl)", L"SENTINEL"); auto a02 = _tryMangleStartingDirectoryForWSL(LR"(wsl -d X)", L"SENTINEL"); auto a03 = _tryMangleStartingDirectoryForWSL(LR"(wsl -d X ~/bin/sh)", L"SENTINEL"); auto a04 = _tryMangleStartingDirectoryForWSL(LR"(wsl.exe)", L"SENTINEL"); auto a05 = _tryMangleStartingDirectoryForWSL(LR"(wsl.exe -d X)", L"SENTINEL"); auto a06 = _tryMangleStartingDirectoryForWSL(LR"(wsl.exe -d X ~/bin/sh)", L"SENTINEL"); auto a07 = _tryMangleStartingDirectoryForWSL(LR"("wsl")", L"SENTINEL"); auto a08 = _tryMangleStartingDirectoryForWSL(LR"("wsl.exe")", L"SENTINEL"); auto a09 = _tryMangleStartingDirectoryForWSL(LR"("wsl" -d X)", L"SENTINEL"); auto a10 = _tryMangleStartingDirectoryForWSL(LR"("wsl.exe" -d X)", L"SENTINEL"); auto a11 = _tryMangleStartingDirectoryForWSL(LR"("C:\Windows\system32\wsl.exe" -d X)", L"SENTINEL"); auto a12 = _tryMangleStartingDirectoryForWSL(LR"("C:\windows\system32\wsl" -d X)", L"SENTINEL"); auto a13 = _tryMangleStartingDirectoryForWSL(LR"(wsl ~/bin)", L"SENTINEL"); // MUST NOT MANGLE auto a14 = _tryMangleStartingDirectoryForWSL(LR"("C:\wsl.exe" -d X)", L"SENTINEL"); auto a15 = _tryMangleStartingDirectoryForWSL(LR"(C:\wsl.exe)", L"SENTINEL"); auto a16 = _tryMangleStartingDirectoryForWSL(LR"(wsl --cd C:\)", L"SENTINEL"); auto a17 = _tryMangleStartingDirectoryForWSL(LR"(wsl ~)", L"SENTINEL"); auto a18 = _tryMangleStartingDirectoryForWSL(LR"(wsl ~ -d Ubuntu)", L"SENTINEL"); ``` We don't have anywhere to put TerminalConnection unit tests :| Closes #592.
2021-08-02 22:39:11 +02:00
newWorkingDirectory,
Switch Connections to use `ValueSet`s to initialize them (#10184) #### ⚠️ targets #10051 ## Summary of the Pull Request This PR does one big, primary thing. It removes all the constructors from any TerminalConnections, and changes them to use an `Initialize` method that accepts a `ValueSet` of properties. Why? For the upcoming window/content process work, we'll need the content process to be able to initialize the connection _in the content process_. However, the window process will be the one that knows what type of connection to make. Enter `ConnectionInformation`. This class will let us specify the class name of the type we want to create, and a set of settings to use when initializing that connection. **IMPORTANT**: As a part of this, the constructor for a connection must have 0 arguments. `RoActivateInstance` lets you just conjure a WinRT type just by class name, but that class must have a 0 arg ctor. Hence the need for `Initialize`, to actually pass the settings. We're using a `ValueSet` here because it's basically a json blob, with more steps. In the future, when extension authors want to have custom connections, we can always deserialize the json into a `ValueSet`, pass it to their connection's `Initialize`, and let then get what they need out of it. ## References * Tear-out: #1256 * Megathread: #5000 * Project: https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760298 * [x] I work here * [n/a] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments `ConnectionInformation` was included as a part of this PR, to demonstrate how this will eventually be used. `ConnectionInformation` is not _currently_ used. ## Validation Steps Performed It still builds and runs.
2021-07-20 17:02:17 +02:00
settings.StartingTitle(),
envMap.GetView(),
::base::saturated_cast<uint32_t>(settings.InitialRows()),
::base::saturated_cast<uint32_t>(settings.InitialCols()),
winrt::guid()));
sessionGuid = conhostConn.Guid();
connection = conhostConn;
}
TraceLoggingWrite(
g_hTerminalAppProvider,
"ConnectionCreated",
TraceLoggingDescription("Event emitted upon the creation of a connection"),
TraceLoggingGuid(connectionType, "ConnectionTypeGuid", "The type of the connection"),
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The profile's GUID"),
TraceLoggingGuid(sessionGuid, "SessionGuid", "The WT_SESSION's GUID"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
return connection;
}
// Method Description:
// - Called when the settings button is clicked. Launches a background
// thread to open the settings file in the default JSON editor.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_SettingsButtonOnClick(const IInspectable&,
const RoutedEventArgs&)
{
Add Cascading User + Default Settings (#2515) 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
2019-09-16 21:57:10 +02:00
const CoreWindow window = CoreWindow::GetForCurrentThread();
// check alt state
const auto rAltState{ window.GetKeyState(VirtualKey::RightMenu) };
const auto lAltState{ window.GetKeyState(VirtualKey::LeftMenu) };
const bool altPressed{ WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) ||
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down) };
// check shift state
const auto shiftState{ window.GetKeyState(VirtualKey::Shift) };
const auto lShiftState{ window.GetKeyState(VirtualKey::LeftShift) };
const auto rShiftState{ window.GetKeyState(VirtualKey::RightShift) };
const auto shiftPressed{ WI_IsFlagSet(shiftState, CoreVirtualKeyStates::Down) ||
WI_IsFlagSet(lShiftState, CoreVirtualKeyStates::Down) ||
WI_IsFlagSet(rShiftState, CoreVirtualKeyStates::Down) };
auto target{ SettingsTarget::SettingsUI };
if (shiftPressed)
{
target = SettingsTarget::SettingsFile;
}
else if (altPressed)
{
target = SettingsTarget::DefaultsFile;
}
_LaunchSettings(target);
}
// Method Description:
// - Called when the command palette button is clicked. Opens the command palette.
void TerminalPage::_CommandPaletteButtonOnClick(const IInspectable&,
const RoutedEventArgs&)
{
CommandPalette().EnableCommandPaletteMode(CommandPaletteLaunchMode::Action);
CommandPalette().Visibility(Visibility::Visible);
}
// Method Description:
// - Called when the about button is clicked. See _ShowAboutDialog for more info.
// Arguments:
// - <unused>
// Return Value:
// - <none>
void TerminalPage::_AboutButtonOnClick(const IInspectable&,
const RoutedEventArgs&)
{
_ShowAboutDialog();
}
// Method Description:
// Called when the users pressed keyBindings while CommandPalette is open.
// Arguments:
// - e: the KeyRoutedEventArgs containing info about the keystroke.
// Return Value:
// - <none>
void TerminalPage::_KeyDownHandler(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
{
const auto key = e.OriginalKey();
const auto scanCode = e.KeyStatus().ScanCode;
const auto coreWindow = CoreWindow::GetForCurrentThread();
const auto ctrlDown = WI_IsFlagSet(coreWindow.GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
const auto altDown = WI_IsFlagSet(coreWindow.GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down);
const auto shiftDown = WI_IsFlagSet(coreWindow.GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down);
winrt::Microsoft::Terminal::Control::KeyChord kc{ ctrlDown, altDown, shiftDown, false, static_cast<int32_t>(key), static_cast<int32_t>(scanCode) };
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
if (const auto cmd{ _settings.ActionMap().GetActionByKeyChord(kc) })
{
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
if (CommandPalette().Visibility() == Visibility::Visible && cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{
CommandPalette().Visibility(Visibility::Collapsed);
}
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
_actionDispatch->DoAction(cmd.ActionAndArgs());
e.Handled(true);
}
}
// Method Description:
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
// - Configure the AppKeyBindings to use our ShortcutActionDispatch and the updated ActionMap
// as the object to handle dispatching ShortcutAction events.
// Arguments:
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
// - bindings: An IActionMapView object to wire up with our event handlers
void TerminalPage::_HookupKeyBindings(const IActionMapView& actionMap) noexcept
{
_bindings->SetDispatch(*_actionDispatch);
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
_bindings->SetActionMap(actionMap);
}
// Method Description:
// - Register our event handlers with our ShortcutActionDispatch. The
// ShortcutActionDispatch is responsible for raising the appropriate
// events for an ActionAndArgs. WE'll handle each possible event in our
// own way.
// Arguments:
// - <none>
void TerminalPage::_RegisterActionCallbacks()
{
// Hook up the ShortcutActionDispatch object's events to our handlers.
// They should all be hooked up here, regardless of whether or not
// there's an actual keychord for them.
Add X Macro for fun and for profit (#9667) **Summary of the Pull Request** This PR adds an X Macro for defining our ShortcutActions. This means that you can add the action in one place, and have the macro synthesize all sorts of boilerplate for you! From the `AllShortcutActions.h` file: > For a clearer explanation of how this file should be used, see: > https://en.wikipedia.org/wiki/X_Macro > > Include this file to be able to quickly define some code in the exact same > way for _every single shortcut action_. To use: > > 1. Include this file > 2. Define the ON_ALL_ACTIONS macro with what you want each action to show up > as. Ex: > > #define ON_ALL_ACTIONS(action) void action##Handler(); > > 3. Then, use the ALL_SHORTCUT_ACTIONS macro to get the ON_ALL_ACTIONS marcro > repeated once for every ShortcutAction > > This is used in KeyMapping.idl, ShortcutAction.*, TerminalPage.*, etc. to > reduce the number of places where we must copy-paste boiler-plate code for > each action. This is _NOT_ something that should be used when any individual > case should be customized. **PR Checklist** * [x] Scratches an itch * [x] I work here * [x] Tests passed * [n/a] Requires documentation to be updated **Detailed Description of the Pull Request / Additional comments** Originally I had this blocked as a follow up to #9662. However, I've grown tired after a month of merging main into this branch, and I'm just shipping it separately. It will inevitably conflict with anyone who has actions in flight currently. **Validation Steps Performed** The code still builds exactly as before!
2021-03-31 18:38:25 +02:00
#define ON_ALL_ACTIONS(action) HOOKUP_ACTION(action);
ALL_SHORTCUT_ACTIONS
#undef ON_ALL_ACTIONS
}
// Method Description:
Decouple "Active Terminal" and "Focused Control" (#3540) ## Summary of the Pull Request Unties the concept of "focused control" from "active control". Previously, we were exclusively using the "Focused" state of `TermControl`s to determine which one was active. This was fraught with gotchas - if anything else became focused, then suddenly there was _no_ pane focused in the Tab. This happened especially frequently if the user clicked on a tab to focus the window. Furthermore, in experimental branches with more UI added to the Terminal (such as [dev/migrie/f/2046-command-palette](https://github.com/microsoft/terminal/tree/dev/migrie/f/2046-command-palette)), when these UIs were added to the Terminal, they'd take focus, which again meant that there was no focused pane. This fixes these issue by having each Tab manually track which Pane is active in that tab. The Tab is now the arbiter of who in the tree is "active". Panes still track this state, for them to be able to MoveFocus appropriately. It also contains a related fix to prevent the tab separator from stealing focus from the TermControl. This required us to set the color of the un-focused Pane border to some color other that Transparent, so I went with the TabViewBackground. Panes now look like the following: ![image](https://user-images.githubusercontent.com/18356694/68697343-41ea2380-0544-11ea-8218-601b57fdd835.png) ## References See also: #2046 ## PR Checklist * [x] Closes #1205 * [x] Closes #522 * [x] Closes #999 * [x] I work here * [😢] Tests added/passed * [n/a] Requires documentation to be updated ## Validation Steps Performed Tested manually opening panes, closing panes, clicking around panes, the whole dance. --------------------------------------------------- * this is janky but is close for some reason? * This is _almost_ right to solve #1205 If I want to double up and also fix #522 (which I do), then I need to also * when a tab GetsFocus, send the focus instead to the Pane * When the border is clicked on, focus that pane's control And like a lot of cleanup, because this is horrifying * hey this autorevoker is really nice * Encapsulate Pane::pfnGotFocus * Propogate the events back up on close * Encapsulate Tab::pfnFocusChanged, and clean up TerminalPage a bit * Mostly just code cleanup, commenting * This works to hittest on the borders If the border is `Transparent`, then it can't hittest for Tapped events, and it'll fall through (to someone) THis at least works, but looks garish * Match the pane border to the TabViewHeader * Fix a bit of dead code and a bad copy-pasta * This _works_ to use a winrt event, but it's dirty * Clean up everything from the winrt::event debacle. * This is dead code that shouldn't have been there * Turn Tab's callback into a winrt::event as well
2019-11-18 22:41:25 +01:00
// - Get the title of the currently focused terminal control. If this tab is
// the focused tab, then also bubble this title to any listeners of our
// TitleChanged event.
// Arguments:
// - tab: the Tab to update the title for.
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
void TerminalPage::_UpdateTitle(const TerminalTab& tab)
{
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
auto newTabTitle = tab.Title();
if (tab == _GetFocusedTab())
{
_TitleChangedHandlers(*this, newTabTitle);
}
}
// Method Description:
// - Connects event handlers to the TermControl for events that we want to
// handle. This includes:
// * the Copy and Paste events, for setting and retrieving clipboard data
// on the right thread
// Arguments:
// - term: The newly created TermControl to connect the events for
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
void TerminalPage::_RegisterTerminalEvents(TermControl term)
{
term.RaiseNotice({ this, &TerminalPage::_ControlNoticeRaisedHandler });
// Add an event handler when the terminal's selection wants to be copied.
// When the text buffer data is retrieved, we'll copy the data into the Clipboard
term.CopyToClipboard({ this, &TerminalPage::_CopyToClipboardHandler });
// Add an event handler when the terminal wants to paste data from the Clipboard.
term.PasteFromClipboard({ this, &TerminalPage::_PasteFromClipboardHandler });
OSC 8 support for conhost and terminal (#7251) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Conhost can now support OSC8 sequences (as specified [here](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)). Terminal also supports those sequences and additionally hyperlinks can be opened by Ctrl+LeftClicking on them. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #204 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [X] Closes #204 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Added support to: - parse OSC8 sequences and extract URIs from them (conhost and terminal) - add hyperlink uri data to textbuffer/screeninformation, associated with a hyperlink id (conhost and terminal) - attach hyperlink ids to text to allow for uri extraction from the textbuffer/screeninformation (conhost and terminal) - process ctrl+leftclick to open a hyperlink in the clicked region if present <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Open up a PowerShell tab and type ```PowerShell ${ESC}=[char]27 Write-Host "${ESC}]8;;https://github.com/microsoft/terminal${ESC}\This is a link!${ESC}]8;;${ESC}\" ``` Ctrl+LeftClick on the link correctly brings you to the terminal page on github ![hyperlink](https://user-images.githubusercontent.com/26824113/89953536-45a6f580-dbfd-11ea-8e0d-8a3cd25c634a.gif)
2020-09-03 19:52:39 +02:00
term.OpenHyperlink({ this, &TerminalPage::_OpenHyperlinkHandler });
term.HidePointerCursor({ get_weak(), &TerminalPage::_HidePointerCursorHandler });
term.RestorePointerCursor({ get_weak(), &TerminalPage::_RestorePointerCursorHandler });
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
// Add an event handler for when the terminal or tab wants to set a
// progress indicator on the taskbar
term.SetTaskbarProgress({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
term.ConnectionStateChanged({ get_weak(), &TerminalPage::_ConnectionStateChangedHandler });
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
}
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
// Method Description:
// - Connects event handlers to the TerminalTab for events that we want to
// handle. This includes:
// * the TitleChanged event, for changing the text of the tab
// * the Color{Selected,Cleared} events to change the color of a tab.
// Arguments:
// - hostingTab: The Tab that's hosting this TermControl instance
void TerminalPage::_RegisterTabEvents(TerminalTab& hostingTab)
{
Enable tab renaming at runtime from the UI (#5775) ## Summary of the Pull Request Adds support for setting, from the UI, a runtime override for the tab title text. The user can use this to effectively "rename" a tab. If set, the tab will _always_ use the runtime override string. If the user has multiple panes with different titles in a pane, then the tab's override text will be used _regardless_ of which pane was focused when the tab was renamed. The override text can be removed by just deleting the entire contents of the box. Then, the tab will revert to using the terminal's usual title. ## References * Wouldn't be possible without the context menu from #3789 * Focus doesn't return to the active terminal after hitting <kbd>enter</kbd>/<kbd>esc</kbd>, but that's tracked by #5750 ## PR Checklist * [x] Closes #1079 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated ## TODO * [x] `Tab::SetTabText` might be able to be greatly simplified/removed? * [x] I'm _pretty sure_ if they set an override title, we won't bubble that up to set the window title. * [x] I'm unsure how this behaves when the terminal's title changes _while_ the TextBox is visible. I don't think it should change the current contents of the box, but it might currently. * [ ] **for discussion**: If the user doesn't actually change the text of the tab, then we probably shouldn't set the override text, right? - EX: if they open the box and the text is "cmd", and immediately hit <kbd>enter</kbd>, then run `title foo`, should the text change to "foo" or stay "cmd"? ## Detailed Description of the Pull Request / Additional comments ![image](https://user-images.githubusercontent.com/18356694/81230615-713f9180-8fb7-11ea-8945-6681eec02a4f.png) ![image](https://user-images.githubusercontent.com/18356694/81230640-7ac8f980-8fb7-11ea-9e6b-22f0e0ed128a.png) ![image](https://user-images.githubusercontent.com/18356694/81230665-86b4bb80-8fb7-11ea-90f0-16d4ffb60d89.png) ![image](https://user-images.githubusercontent.com/18356694/81230686-9207e700-8fb7-11ea-94a9-f3f5a59be139.png) ![image](https://user-images.githubusercontent.com/18356694/81230732-a350f380-8fb7-11ea-9901-6dd4f36154f1.png) ![image](https://user-images.githubusercontent.com/18356694/81230746-a8ae3e00-8fb7-11ea-94fa-d2578f9241a7.png) ![image](https://user-images.githubusercontent.com/18356694/81230787-bc59a480-8fb7-11ea-8edf-2bd7fad343fc.png) ![image](https://user-images.githubusercontent.com/18356694/81230851-dc896380-8fb7-11ea-98c1-918b943543e4.png)
2020-05-28 23:06:17 +02:00
auto weakTab{ hostingTab.get_weak() };
auto weakThis{ get_weak() };
// PropertyChanged is the generic mechanism by which the Tab
// communicates changes to any of its observable properties, including
// the Title
hostingTab.PropertyChanged([weakTab, weakThis](auto&&, const WUX::Data::PropertyChangedEventArgs& args) {
Fixed self reference capture in Tab and TerminalPage (#3835) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Every lambda capture in `Tab` and `TerminalPage` has been changed from capturing raw `this` to `std::weak_ptr<Tab>` or `winrt::weak_ref<TerminalPage>`. Lambda bodies have been changed to check the weak reference before use. Capturing raw `this` in `Tab`'s [title change event handler](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/Tab.cpp#L299) was the root cause of #3776, and is fixed in this PR among other instance of raw `this` capture. The lambda fixes to `TerminalPage` are unrelated to the core issue addressed in the PR checklist. Because I was already editing `TerminalPage`, figured I'd do a [weak_ref pass](https://github.com/microsoft/terminal/issues/3776#issuecomment-560575575). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3776, potentially #2248, likely closes others * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3776 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments `Tab` now inherits from `enable_shared_from_this`, which enable accessing `Tab` objects as `std::weak_ptr<Tab>` objects. All instances of lambdas capturing `this` now capture `std::weak_ptr<Tab>` instead. `TerminalPage` is a WinRT type which supports `winrt::weak_ref<TerminalPage>`. All previous instance of `TerminalPage` lambdas capturing `this` has been replaced to capture `winrt::weak_ref<TerminalPage>`. These weak pointers/references can only be created after object construction necessitating for `Tab` a new function called after construction to bind lambdas. Any anomalous crash related to the following functionality during closing a tab or WT may be fixed by this PR: - Tab icon updating - Tab text updating - Tab dragging - Clicking new tab button - Changing active pane - Closing an active tab - Clicking on a tab - Creating the new tab flyout menu Sorry about all the commits. Will fix my fork after this PR! 😅 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Attempted to repro the steps indicated in issue #3776 with the new changes and failed. When before the changes, the issue could consistently be reproed.
2019-12-06 00:18:22 +01:00
auto page{ weakThis.get() };
auto tab{ weakTab.get() };
Fixed self reference capture in Tab and TerminalPage (#3835) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Every lambda capture in `Tab` and `TerminalPage` has been changed from capturing raw `this` to `std::weak_ptr<Tab>` or `winrt::weak_ref<TerminalPage>`. Lambda bodies have been changed to check the weak reference before use. Capturing raw `this` in `Tab`'s [title change event handler](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/Tab.cpp#L299) was the root cause of #3776, and is fixed in this PR among other instance of raw `this` capture. The lambda fixes to `TerminalPage` are unrelated to the core issue addressed in the PR checklist. Because I was already editing `TerminalPage`, figured I'd do a [weak_ref pass](https://github.com/microsoft/terminal/issues/3776#issuecomment-560575575). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3776, potentially #2248, likely closes others * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3776 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments `Tab` now inherits from `enable_shared_from_this`, which enable accessing `Tab` objects as `std::weak_ptr<Tab>` objects. All instances of lambdas capturing `this` now capture `std::weak_ptr<Tab>` instead. `TerminalPage` is a WinRT type which supports `winrt::weak_ref<TerminalPage>`. All previous instance of `TerminalPage` lambdas capturing `this` has been replaced to capture `winrt::weak_ref<TerminalPage>`. These weak pointers/references can only be created after object construction necessitating for `Tab` a new function called after construction to bind lambdas. Any anomalous crash related to the following functionality during closing a tab or WT may be fixed by this PR: - Tab icon updating - Tab text updating - Tab dragging - Clicking new tab button - Changing active pane - Closing an active tab - Clicking on a tab - Creating the new tab flyout menu Sorry about all the commits. Will fix my fork after this PR! 😅 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Attempted to repro the steps indicated in issue #3776 with the new changes and failed. When before the changes, the issue could consistently be reproed.
2019-12-06 00:18:22 +01:00
if (page && tab)
{
Enable tab renaming at runtime from the UI (#5775) ## Summary of the Pull Request Adds support for setting, from the UI, a runtime override for the tab title text. The user can use this to effectively "rename" a tab. If set, the tab will _always_ use the runtime override string. If the user has multiple panes with different titles in a pane, then the tab's override text will be used _regardless_ of which pane was focused when the tab was renamed. The override text can be removed by just deleting the entire contents of the box. Then, the tab will revert to using the terminal's usual title. ## References * Wouldn't be possible without the context menu from #3789 * Focus doesn't return to the active terminal after hitting <kbd>enter</kbd>/<kbd>esc</kbd>, but that's tracked by #5750 ## PR Checklist * [x] Closes #1079 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated ## TODO * [x] `Tab::SetTabText` might be able to be greatly simplified/removed? * [x] I'm _pretty sure_ if they set an override title, we won't bubble that up to set the window title. * [x] I'm unsure how this behaves when the terminal's title changes _while_ the TextBox is visible. I don't think it should change the current contents of the box, but it might currently. * [ ] **for discussion**: If the user doesn't actually change the text of the tab, then we probably shouldn't set the override text, right? - EX: if they open the box and the text is "cmd", and immediately hit <kbd>enter</kbd>, then run `title foo`, should the text change to "foo" or stay "cmd"? ## Detailed Description of the Pull Request / Additional comments ![image](https://user-images.githubusercontent.com/18356694/81230615-713f9180-8fb7-11ea-8945-6681eec02a4f.png) ![image](https://user-images.githubusercontent.com/18356694/81230640-7ac8f980-8fb7-11ea-9e6b-22f0e0ed128a.png) ![image](https://user-images.githubusercontent.com/18356694/81230665-86b4bb80-8fb7-11ea-90f0-16d4ffb60d89.png) ![image](https://user-images.githubusercontent.com/18356694/81230686-9207e700-8fb7-11ea-94a9-f3f5a59be139.png) ![image](https://user-images.githubusercontent.com/18356694/81230732-a350f380-8fb7-11ea-9901-6dd4f36154f1.png) ![image](https://user-images.githubusercontent.com/18356694/81230746-a8ae3e00-8fb7-11ea-94fa-d2578f9241a7.png) ![image](https://user-images.githubusercontent.com/18356694/81230787-bc59a480-8fb7-11ea-8edf-2bd7fad343fc.png) ![image](https://user-images.githubusercontent.com/18356694/81230851-dc896380-8fb7-11ea-98c1-918b943543e4.png)
2020-05-28 23:06:17 +02:00
if (args.PropertyName() == L"Title")
{
page->_UpdateTitle(*tab);
}
Fix `exit`ing a zoomed pane (#7973) ## Summary of the Pull Request Fixes the bug where `exit`ing inside a closed pane would leave the Terminal blank. Additionally, removes `Tab::GetRootElement` and replaces it with the _observable_ `Tab::Content`. This should be more resilient in the future. Also adds some tests, though admittedly not for this exact scenario. This scenario requires a cooperating TerminalConnection that I can drive for the sake of testing, and _ain't nobody got time for that_. ## References * Introduced in #6989 ## PR Checklist * [x] Closes #7252 * [x] I work here * [x] Tests added/passed 🎉 * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments From notes I had left in `Tab.cpp` while I was working on this: ``` OKAY I see what's happening here the ActivePaneChanged Handler in TerminalPage doesn't re-attach the tab content to the tree, it just updates the title of the window. So when the pane is `exit`ed, the pane's control is removed and re-attached to the parent grid, which _isn't in the XAML tree_. And no one can go tell the TerminalPage that it needs to re set up the tab content again. The Page _manually_ does this in a few places, when various pane actions are about to take place, it'll unzoom. It would be way easier if the Tab could just manage the content of the page. Or if the Tab just had a Content that was observable, that when that changed, the page would auto readjust. That does sound like a LOT of work though. ``` ## Validation Steps Performed Opened panes, closed panes, exited panes, zoomed panes, moved focus between panes, panes, panes, panes
2020-10-21 23:33:56 +02:00
else if (args.PropertyName() == L"Content")
{
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
if (*tab == page->_GetFocusedTab())
Fix `exit`ing a zoomed pane (#7973) ## Summary of the Pull Request Fixes the bug where `exit`ing inside a closed pane would leave the Terminal blank. Additionally, removes `Tab::GetRootElement` and replaces it with the _observable_ `Tab::Content`. This should be more resilient in the future. Also adds some tests, though admittedly not for this exact scenario. This scenario requires a cooperating TerminalConnection that I can drive for the sake of testing, and _ain't nobody got time for that_. ## References * Introduced in #6989 ## PR Checklist * [x] Closes #7252 * [x] I work here * [x] Tests added/passed 🎉 * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments From notes I had left in `Tab.cpp` while I was working on this: ``` OKAY I see what's happening here the ActivePaneChanged Handler in TerminalPage doesn't re-attach the tab content to the tree, it just updates the title of the window. So when the pane is `exit`ed, the pane's control is removed and re-attached to the parent grid, which _isn't in the XAML tree_. And no one can go tell the TerminalPage that it needs to re set up the tab content again. The Page _manually_ does this in a few places, when various pane actions are about to take place, it'll unzoom. It would be way easier if the Tab could just manage the content of the page. Or if the Tab just had a Content that was observable, that when that changed, the page would auto readjust. That does sound like a LOT of work though. ``` ## Validation Steps Performed Opened panes, closed panes, exited panes, zoomed panes, moved focus between panes, panes, panes, panes
2020-10-21 23:33:56 +02:00
{
page->_tabContent.Children().Clear();
page->_tabContent.Children().Append(tab->Content());
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
tab->Focus(FocusState::Programmatic);
Fix `exit`ing a zoomed pane (#7973) ## Summary of the Pull Request Fixes the bug where `exit`ing inside a closed pane would leave the Terminal blank. Additionally, removes `Tab::GetRootElement` and replaces it with the _observable_ `Tab::Content`. This should be more resilient in the future. Also adds some tests, though admittedly not for this exact scenario. This scenario requires a cooperating TerminalConnection that I can drive for the sake of testing, and _ain't nobody got time for that_. ## References * Introduced in #6989 ## PR Checklist * [x] Closes #7252 * [x] I work here * [x] Tests added/passed 🎉 * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments From notes I had left in `Tab.cpp` while I was working on this: ``` OKAY I see what's happening here the ActivePaneChanged Handler in TerminalPage doesn't re-attach the tab content to the tree, it just updates the title of the window. So when the pane is `exit`ed, the pane's control is removed and re-attached to the parent grid, which _isn't in the XAML tree_. And no one can go tell the TerminalPage that it needs to re set up the tab content again. The Page _manually_ does this in a few places, when various pane actions are about to take place, it'll unzoom. It would be way easier if the Tab could just manage the content of the page. Or if the Tab just had a Content that was observable, that when that changed, the page would auto readjust. That does sound like a LOT of work though. ``` ## Validation Steps Performed Opened panes, closed panes, exited panes, zoomed panes, moved focus between panes, panes, panes, panes
2020-10-21 23:33:56 +02:00
}
}
}
});
// react on color changed events
Enable tab renaming at runtime from the UI (#5775) ## Summary of the Pull Request Adds support for setting, from the UI, a runtime override for the tab title text. The user can use this to effectively "rename" a tab. If set, the tab will _always_ use the runtime override string. If the user has multiple panes with different titles in a pane, then the tab's override text will be used _regardless_ of which pane was focused when the tab was renamed. The override text can be removed by just deleting the entire contents of the box. Then, the tab will revert to using the terminal's usual title. ## References * Wouldn't be possible without the context menu from #3789 * Focus doesn't return to the active terminal after hitting <kbd>enter</kbd>/<kbd>esc</kbd>, but that's tracked by #5750 ## PR Checklist * [x] Closes #1079 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated ## TODO * [x] `Tab::SetTabText` might be able to be greatly simplified/removed? * [x] I'm _pretty sure_ if they set an override title, we won't bubble that up to set the window title. * [x] I'm unsure how this behaves when the terminal's title changes _while_ the TextBox is visible. I don't think it should change the current contents of the box, but it might currently. * [ ] **for discussion**: If the user doesn't actually change the text of the tab, then we probably shouldn't set the override text, right? - EX: if they open the box and the text is "cmd", and immediately hit <kbd>enter</kbd>, then run `title foo`, should the text change to "foo" or stay "cmd"? ## Detailed Description of the Pull Request / Additional comments ![image](https://user-images.githubusercontent.com/18356694/81230615-713f9180-8fb7-11ea-8945-6681eec02a4f.png) ![image](https://user-images.githubusercontent.com/18356694/81230640-7ac8f980-8fb7-11ea-9e6b-22f0e0ed128a.png) ![image](https://user-images.githubusercontent.com/18356694/81230665-86b4bb80-8fb7-11ea-90f0-16d4ffb60d89.png) ![image](https://user-images.githubusercontent.com/18356694/81230686-9207e700-8fb7-11ea-94a9-f3f5a59be139.png) ![image](https://user-images.githubusercontent.com/18356694/81230732-a350f380-8fb7-11ea-9901-6dd4f36154f1.png) ![image](https://user-images.githubusercontent.com/18356694/81230746-a8ae3e00-8fb7-11ea-94fa-d2578f9241a7.png) ![image](https://user-images.githubusercontent.com/18356694/81230787-bc59a480-8fb7-11ea-8edf-2bd7fad343fc.png) ![image](https://user-images.githubusercontent.com/18356694/81230851-dc896380-8fb7-11ea-98c1-918b943543e4.png)
2020-05-28 23:06:17 +02:00
hostingTab.ColorSelected([weakTab, weakThis](auto&& color) {
auto page{ weakThis.get() };
auto tab{ weakTab.get() };
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
if (page && tab && (tab->FocusState() != FocusState::Unfocused))
{
page->_SetNonClientAreaColors(color);
}
});
Enable tab renaming at runtime from the UI (#5775) ## Summary of the Pull Request Adds support for setting, from the UI, a runtime override for the tab title text. The user can use this to effectively "rename" a tab. If set, the tab will _always_ use the runtime override string. If the user has multiple panes with different titles in a pane, then the tab's override text will be used _regardless_ of which pane was focused when the tab was renamed. The override text can be removed by just deleting the entire contents of the box. Then, the tab will revert to using the terminal's usual title. ## References * Wouldn't be possible without the context menu from #3789 * Focus doesn't return to the active terminal after hitting <kbd>enter</kbd>/<kbd>esc</kbd>, but that's tracked by #5750 ## PR Checklist * [x] Closes #1079 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated ## TODO * [x] `Tab::SetTabText` might be able to be greatly simplified/removed? * [x] I'm _pretty sure_ if they set an override title, we won't bubble that up to set the window title. * [x] I'm unsure how this behaves when the terminal's title changes _while_ the TextBox is visible. I don't think it should change the current contents of the box, but it might currently. * [ ] **for discussion**: If the user doesn't actually change the text of the tab, then we probably shouldn't set the override text, right? - EX: if they open the box and the text is "cmd", and immediately hit <kbd>enter</kbd>, then run `title foo`, should the text change to "foo" or stay "cmd"? ## Detailed Description of the Pull Request / Additional comments ![image](https://user-images.githubusercontent.com/18356694/81230615-713f9180-8fb7-11ea-8945-6681eec02a4f.png) ![image](https://user-images.githubusercontent.com/18356694/81230640-7ac8f980-8fb7-11ea-9e6b-22f0e0ed128a.png) ![image](https://user-images.githubusercontent.com/18356694/81230665-86b4bb80-8fb7-11ea-90f0-16d4ffb60d89.png) ![image](https://user-images.githubusercontent.com/18356694/81230686-9207e700-8fb7-11ea-94a9-f3f5a59be139.png) ![image](https://user-images.githubusercontent.com/18356694/81230732-a350f380-8fb7-11ea-9901-6dd4f36154f1.png) ![image](https://user-images.githubusercontent.com/18356694/81230746-a8ae3e00-8fb7-11ea-94fa-d2578f9241a7.png) ![image](https://user-images.githubusercontent.com/18356694/81230787-bc59a480-8fb7-11ea-8edf-2bd7fad343fc.png) ![image](https://user-images.githubusercontent.com/18356694/81230851-dc896380-8fb7-11ea-98c1-918b943543e4.png)
2020-05-28 23:06:17 +02:00
hostingTab.ColorCleared([weakTab, weakThis]() {
auto page{ weakThis.get() };
auto tab{ weakTab.get() };
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
if (page && tab && (tab->FocusState() != FocusState::Unfocused))
{
page->_ClearNonClientAreaColors();
}
});
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
// Add an event handler for when the terminal or tab wants to set a
// progress indicator on the taskbar
hostingTab.TaskbarProgressChanged({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
// TODO GH#3327: Once we support colorizing the NewTab button based on
// the color of the tab, we'll want to make sure to call
// _ClearNewTabButtonColor here, to reset it to the default (for the
// newly created tab).
// remove any colors left by other colored tabs
// _ClearNewTabButtonColor();
}
// Method Description:
// - Helper to manually exit "zoom" when certain actions take place.
// Anything that modifies the state of the pane tree should probably
// un-zoom the focused pane first, so that the user can see the full pane
// tree again. These actions include:
// * Splitting a new pane
// * Closing a pane
// * Moving focus between panes
// * Resizing a pane
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_UnZoomIfNeeded()
{
if (const auto activeTab{ _GetFocusedTabImpl() })
{
if (activeTab->IsZoomed())
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
{
// Remove the content from the tab first, so Pane::UnZoom can
// re-attach the content to the tree w/in the pane
_tabContent.Children().Clear();
// In ExitZoom, we'll change the Tab's Content(), triggering the
// content changed event, which will re-attach the tab's new content
// root to the tree.
activeTab->ExitZoom();
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
}
}
}
// Method Description:
// - Attempt to move focus between panes, as to focus the child on
// the other side of the separator. See Pane::NavigateFocus for details.
// - Moves the focus of the currently focused tab.
// Arguments:
// - direction: The direction to move the focus in.
// Return Value:
Passing through moveFocus keys when moving to another pane failed (#10806) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Implementation of #6219 with a small tweak, not just passing the keys when no panes are present, but passing on the keys when there is no other pane to move to. This enables another usecase: 2 panes in terminal split vertically; in one of these panes running tmux with two panes that are split horizontally. This allows the user to still navigate between tmux panes even though they have terminal panes open. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References Not that I know of <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #6219 * [x] CLA signed. * [x] Tests added/passed * [x] Documentation updated. I don't think that's necessary * [x] Schema updated. N/A * [ ] 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. <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Implementation by propagating the boolean indicating success of moving focus all the way to the action handler, where this result will determine whether the action will be considered handled or not. When the action is not handled, the keychord will be propagated to the terminal. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing; all relevant unit tests still work
2021-07-29 00:05:32 +02:00
// - Whether changing the focus succeeded. This allows a keychord to propagate
// to the terminal when no other panes are present (GH#6219)
bool TerminalPage::_MoveFocus(const FocusDirection& direction)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
Passing through moveFocus keys when moving to another pane failed (#10806) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Implementation of #6219 with a small tweak, not just passing the keys when no panes are present, but passing on the keys when there is no other pane to move to. This enables another usecase: 2 panes in terminal split vertically; in one of these panes running tmux with two panes that are split horizontally. This allows the user to still navigate between tmux panes even though they have terminal panes open. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References Not that I know of <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #6219 * [x] CLA signed. * [x] Tests added/passed * [x] Documentation updated. I don't think that's necessary * [x] Schema updated. N/A * [ ] 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. <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Implementation by propagating the boolean indicating success of moving focus all the way to the action handler, where this result will determine whether the action will be considered handled or not. When the action is not handled, the keychord will be propagated to the terminal. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing; all relevant unit tests still work
2021-07-29 00:05:32 +02:00
return terminalTab->NavigateFocus(direction);
}
Passing through moveFocus keys when moving to another pane failed (#10806) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Implementation of #6219 with a small tweak, not just passing the keys when no panes are present, but passing on the keys when there is no other pane to move to. This enables another usecase: 2 panes in terminal split vertically; in one of these panes running tmux with two panes that are split horizontally. This allows the user to still navigate between tmux panes even though they have terminal panes open. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References Not that I know of <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #6219 * [x] CLA signed. * [x] Tests added/passed * [x] Documentation updated. I don't think that's necessary * [x] Schema updated. N/A * [ ] 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. <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Implementation by propagating the boolean indicating success of moving focus all the way to the action handler, where this result will determine whether the action will be considered handled or not. When the action is not handled, the keychord will be propagated to the terminal. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing; all relevant unit tests still work
2021-07-29 00:05:32 +02:00
return false;
}
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References This work potentially touches on: #1000 #2398 and #4922 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality) * [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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes. Work currently done: - Add boilerplate/infrastructure for argument parsing, hotkeys, event handling - Adds the `MovePane` function that finds the focused pane, and then tries to find a pane that is visually adjacent to according to direction. - First pass at the `SwapPanes` function that swaps the tree location of two panes - First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus` that search the tree for the currently focused pane, and then climbs back up the tree to try to find a sibling pane that is adjacent to it. - An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction. Next steps: - Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function. - Do we want default hotkeys for the new actions? <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 14:53:03 +02:00
// Method Description:
// - Attempt to swap the positions of the focused pane with another pane.
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
// See Pane::SwapPane for details.
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References This work potentially touches on: #1000 #2398 and #4922 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality) * [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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes. Work currently done: - Add boilerplate/infrastructure for argument parsing, hotkeys, event handling - Adds the `MovePane` function that finds the focused pane, and then tries to find a pane that is visually adjacent to according to direction. - First pass at the `SwapPanes` function that swaps the tree location of two panes - First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus` that search the tree for the currently focused pane, and then climbs back up the tree to try to find a sibling pane that is adjacent to it. - An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction. Next steps: - Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function. - Do we want default hotkeys for the new actions? <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 14:53:03 +02:00
// Arguments:
// - direction: The direction to move the focused pane in.
// Return Value:
// - true if panes were swapped.
bool TerminalPage::_SwapPane(const FocusDirection& direction)
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References This work potentially touches on: #1000 #2398 and #4922 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality) * [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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes. Work currently done: - Add boilerplate/infrastructure for argument parsing, hotkeys, event handling - Adds the `MovePane` function that finds the focused pane, and then tries to find a pane that is visually adjacent to according to direction. - First pass at the `SwapPanes` function that swaps the tree location of two panes - First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus` that search the tree for the currently focused pane, and then climbs back up the tree to try to find a sibling pane that is adjacent to it. - An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction. Next steps: - Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function. - Do we want default hotkeys for the new actions? <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 14:53:03 +02:00
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
_UnZoomIfNeeded();
return terminalTab->SwapPane(direction);
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References This work potentially touches on: #1000 #2398 and #4922 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality) * [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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes. Work currently done: - Add boilerplate/infrastructure for argument parsing, hotkeys, event handling - Adds the `MovePane` function that finds the focused pane, and then tries to find a pane that is visually adjacent to according to direction. - First pass at the `SwapPanes` function that swaps the tree location of two panes - First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus` that search the tree for the currently focused pane, and then climbs back up the tree to try to find a sibling pane that is adjacent to it. - An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction. Next steps: - Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function. - Do we want default hotkeys for the new actions? <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 14:53:03 +02:00
}
return false;
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References This work potentially touches on: #1000 #2398 and #4922 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality) * [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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes. Work currently done: - Add boilerplate/infrastructure for argument parsing, hotkeys, event handling - Adds the `MovePane` function that finds the focused pane, and then tries to find a pane that is visually adjacent to according to direction. - First pass at the `SwapPanes` function that swaps the tree location of two panes - First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus` that search the tree for the currently focused pane, and then climbs back up the tree to try to find a sibling pane that is adjacent to it. - An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction. Next steps: - Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function. - Do we want default hotkeys for the new actions? <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 14:53:03 +02:00
}
TermControl TerminalPage::_GetActiveControl()
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
return terminalTab->GetActiveTerminalControl();
}
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
return nullptr;
}
// Method Description:
// - Warn the user that they are about to close all open windows, then
// signal that we want to close everything.
fire_and_forget TerminalPage::RequestQuit()
{
if (!_displayingCloseDialog)
{
_displayingCloseDialog = true;
ContentDialogResult warningResult = co_await _ShowQuitDialog();
_displayingCloseDialog = false;
if (warningResult != ContentDialogResult::Primary)
{
co_return;
}
_QuitRequestedHandlers(nullptr, nullptr);
}
}
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
// Method Description:
// - Saves the window position and tab layout to the application state
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
// - This does not create the InitialPosition field, that needs to be
// added externally.
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
// Arguments:
// - <none>
// Return Value:
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
// - the window layout
WindowLayout TerminalPage::GetWindowLayout()
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
{
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
if (_startupState != StartupState::Initialized)
{
return nullptr;
}
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
std::vector<ActionAndArgs> actions;
for (auto tab : _tabs)
{
if (auto terminalTab = _GetTerminalTabImpl(tab))
{
auto tabActions = terminalTab->BuildStartupActions();
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
actions.insert(actions.end(), std::make_move_iterator(tabActions.begin()), std::make_move_iterator(tabActions.end()));
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
}
else if (tab.try_as<SettingsTab>())
{
ActionAndArgs action;
action.Action(ShortcutAction::OpenSettings);
OpenSettingsArgs args{ SettingsTarget::SettingsUI };
action.Args(args);
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
actions.emplace_back(std::move(action));
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
}
}
// if the focused tab was not the last tab, restore that
auto idx = _GetFocusedTabIndex();
if (idx && idx != _tabs.Size() - 1)
{
ActionAndArgs action;
action.Action(ShortcutAction::SwitchToTab);
SwitchToTabArgs switchToTabArgs{ idx.value() };
action.Args(switchToTabArgs);
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
actions.emplace_back(std::move(action));
}
// If the user set a custom name, save it
if (_WindowName != L"")
{
ActionAndArgs action;
action.Action(ShortcutAction::RenameWindow);
RenameWindowArgs args{ _WindowName };
action.Args(args);
actions.emplace_back(std::move(action));
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
}
WindowLayout layout{};
layout.TabLayout(winrt::single_threaded_vector<ActionAndArgs>(std::move(actions)));
// Only save the content size because the tab size will be added on load.
const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
const float contentHeight = ::base::saturated_cast<float>(_tabContent.ActualHeight());
const winrt::Windows::Foundation::Size windowSize{ contentWidth, contentHeight };
layout.InitialSize(windowSize);
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
return layout;
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
}
// Method Description:
// - Close the terminal app. If there is more
// than one tab opened, show a warning dialog.
// Arguments:
// - bypassDialog: if true a dialog won't be shown even if the user would
// normally get confirmation. This is used in the case where the user
// has already been prompted by the Quit action.
fire_and_forget TerminalPage::CloseWindow(bool bypassDialog)
{
if (!bypassDialog &&
_HasMultipleTabs() &&
minor refactor: Move Tab management into its own file (#9629) I think we can all agree that `TerminalPage.cpp` is an unruly beast of a file. It's got everything. It does everything. It can sometimes be a bit hard to work with, because of simply how big it is. This PR tries to alleviate this by making `TerminalPage.cpp` just a little smaller. It does so by moving pretty much everything related to tab management into its own file, `TabManagement.cpp`. These methods that have moved are all the same as they were before, and they're still members of `TerminalPage`. But now they're all in one place. I tried to move all the references to `_tabs` in `TerminalPage.cpp`, but there's still a few that I left behind. Mostly because I felt that moving those would be too gnarly a code change for an otherwise simple cut&paste PR. There are a few new methods I introduced: * `_TabDragStarted` and `_TabDragCompleted`: These were lambdas before, promoted to full methods. * `_DismissTabContextMenus`: Remove all the right-click context menus from the tabs * `_FocusCurrentTab`: This one's a bit trickier, we were actually doing this in a few different places, so I tried consolidating. * `_HasMultipleTabs`: This doesn't need explaining. * `_RemoveAllTabs`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` * `_ResizeTabContent`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` In the future, some enterprising young soul could try promoting that file to its own class, and hiding `_tabs` (and `_mruTabs`) inside it. Probably would need to take a reference to TerminalPage's `_tabView` and `_newTabButton`. I'm not doing that right now, because I already hate the idea of the ... > 920 additions and 847 deletions. ... I'm making you look at already. ## Other thoughts Some of the calls might be a little arbitrary - `_OpenNewTab` and `_CreateNewTabFromSettings` probably should stay in `TerminalPage`? Or at least elements of those might need to get split up better. Similarly `TerminalPage::_OpenSettingsUI` stayed in `TerminalPage.cpp`, but it does a lot of the same work as `_CreateNewTabFromSettings`. I'm not saying this is the definitive places for these methods - it's code we're working with, not stone ☺️
2021-03-29 21:53:39 +02:00
_settings.GlobalSettings().ConfirmCloseAllTabs() &&
!_displayingCloseDialog)
{
Double middle click on taskbar preview closes application (#7871) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request A second close command (middle click on taskbar preview) overrides the warning dialog and closes the application. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7451 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments When a close command is invoked (middle click on taskbar preview or 'X' button), a new flag is set. When the user wants to close again (this time only via the taskbar preview, as the 'X' button is disabled), the application is closed. If the user cancels the dialog, the flag is reset to prevent accidental closing on a subsequent close command. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed I am developing with a [Windows 10 virtual machine](https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/) provided by Microsoft. I tested manually. I considered the 'X' button, middle click on taskbar preview, and Alt+F4. Only a middle click on the taskbar preview does override the dialog.
2020-10-29 17:32:12 +01:00
_displayingCloseDialog = true;
ContentDialogResult warningResult = co_await _ShowCloseWarningDialog();
_displayingCloseDialog = false;
if (warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
if (ShouldUsePersistedLayout(_settings))
{
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
// Don't delete the ApplicationState when all of the tabs are removed.
// If there is still a monarch living they will get the event that
// a window closed and trigger a new save without this window.
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
_maintainStateOnTabClose = true;
}
minor refactor: Move Tab management into its own file (#9629) I think we can all agree that `TerminalPage.cpp` is an unruly beast of a file. It's got everything. It does everything. It can sometimes be a bit hard to work with, because of simply how big it is. This PR tries to alleviate this by making `TerminalPage.cpp` just a little smaller. It does so by moving pretty much everything related to tab management into its own file, `TabManagement.cpp`. These methods that have moved are all the same as they were before, and they're still members of `TerminalPage`. But now they're all in one place. I tried to move all the references to `_tabs` in `TerminalPage.cpp`, but there's still a few that I left behind. Mostly because I felt that moving those would be too gnarly a code change for an otherwise simple cut&paste PR. There are a few new methods I introduced: * `_TabDragStarted` and `_TabDragCompleted`: These were lambdas before, promoted to full methods. * `_DismissTabContextMenus`: Remove all the right-click context menus from the tabs * `_FocusCurrentTab`: This one's a bit trickier, we were actually doing this in a few different places, so I tried consolidating. * `_HasMultipleTabs`: This doesn't need explaining. * `_RemoveAllTabs`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` * `_ResizeTabContent`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` In the future, some enterprising young soul could try promoting that file to its own class, and hiding `_tabs` (and `_mruTabs`) inside it. Probably would need to take a reference to TerminalPage's `_tabView` and `_newTabButton`. I'm not doing that right now, because I already hate the idea of the ... > 920 additions and 847 deletions. ... I'm making you look at already. ## Other thoughts Some of the calls might be a little arbitrary - `_OpenNewTab` and `_CreateNewTabFromSettings` probably should stay in `TerminalPage`? Or at least elements of those might need to get split up better. Similarly `TerminalPage::_OpenSettingsUI` stayed in `TerminalPage.cpp`, but it does a lot of the same work as `_CreateNewTabFromSettings`. I'm not saying this is the definitive places for these methods - it's code we're working with, not stone ☺️
2021-03-29 21:53:39 +02:00
_RemoveAllTabs();
}
// Method Description:
// - Move the viewport of the terminal of the currently focused tab up or
// down a number of lines.
// Arguments:
// - scrollDirection: ScrollUp will move the viewport up, ScrollDown will move the viewport down
// - rowsToScroll: a number of lines to move the viewport. If not provided we will use a system default.
void TerminalPage::_Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
uint32_t realRowsToScroll;
if (rowsToScroll == nullptr)
{
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
terminalTab->GetActiveTerminalControl().ViewHeight() :
_systemRowsToScroll;
}
else
{
// use the custom value specified in the command
realRowsToScroll = rowsToScroll.Value();
}
auto scrollDelta = _ComputeScrollDelta(scrollDirection, realRowsToScroll);
terminalTab->Scroll(scrollDelta);
}
}
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
// Method Description:
// - Moves the currently active pane on the currently active tab to the
// specified tab. If the tab index is greater than the number of
// tabs, then a new tab will be created for the pane. Similarly, if a pane
// is the last remaining pane on a tab, that tab will be closed upon moving.
// - No move will occur if the tabIdx is the same as the current tab, or if
// the specified tab is not a host of terminals (such as the settings tab).
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
// Arguments:
// - tabIdx: The target tab index.
// Return Value:
// - true if the pane was successfully moved to the new tab.
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
bool TerminalPage::_MovePane(const uint32_t tabIdx)
{
auto focusedTab{ _GetFocusedTabImpl() };
if (!focusedTab)
{
return false;
}
// If we are trying to move from the current tab to the current tab do nothing.
if (_GetFocusedTabIndex() == tabIdx)
{
return false;
}
// Moving the pane from the current tab might close it, so get the next
// tab before its index changes.
if (_tabs.Size() > tabIdx)
{
auto targetTab = _GetTerminalTabImpl(_tabs.GetAt(tabIdx));
// if the selected tab is not a host of terminals (e.g. settings)
// don't attempt to add a pane to it.
if (!targetTab)
{
return false;
}
auto pane = focusedTab->DetachPane();
targetTab->AttachPane(pane);
_SetFocusedTab(*targetTab);
}
else
{
auto pane = focusedTab->DetachPane();
_CreateNewTabFromPane(pane);
}
return true;
}
// Method Description:
// - Split the focused pane either horizontally or vertically, and place the
// given TermControl into the newly created pane.
// Arguments:
Add the ability to split a pane and put the new pane first. (#11145) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds directional modifiers for SplitState and convert those to the appropriate horizontal/vertical when splitting a pane. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #4340 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments "vertical" and "horizontal" splits were removed from `defaults.json`, but code was added to parse those as `right` and `down` respectively. It is also the case that if a user has a custom hotkey for `split: vertical` it will override the default for `split: right`. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Split the pane using each of the new directional movements
2021-09-15 22:14:57 +02:00
// - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the
// new pane should be split from its parent.
// - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane.
Add support for new panes with specifc profiles and other settings overrides (#3825) ## Summary of the Pull Request This enables the user to set a number of extra settings in the `NewTab` and `SplitPane` `ShortcutAction`s, that enable customizing how a new terminal is created at runtime. The following four properties were added: * `profile` * `commandline` * `tabTitle` * `startingDirectory` `profile` can be used with either a GUID or the name of a profile, and the action will launch that profile instead of the default. `commandline`, `tabTitle`, and `startingDirectory` can all be used to override the profile's values of those settings. This will be more useful for #607. With this PR, you can make bindings like the following: ```json { "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" } }, { "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "vertical", "profile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}" } }, { "keys": ["ctrl+c"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile1" } }, { "keys": ["ctrl+d"], "command": { "action": "splitPane", "split": "vertical", "profile": "profile2" } }, { "keys": ["ctrl+e"], "command": { "action": "splitPane", "split": "horizontal", "commandline": "foo.exe" } }, { "keys": ["ctrl+f"], "command": { "action": "splitPane", "split": "horizontal", "profile": "profile1", "commandline": "foo.exe" } }, { "keys": ["ctrl+g"], "command": { "action": "newTab" } }, { "keys": ["ctrl+h"], "command": { "action": "newTab", "startingDirectory": "c:\\foo" } }, { "keys": ["ctrl+i"], "command": { "action": "newTab", "profile": "profile2", "startingDirectory": "c:\\foo" } }, { "keys": ["ctrl+j"], "command": { "action": "newTab", "tabTitle": "bar" } }, { "keys": ["ctrl+k"], "command": { "action": "newTab", "profile": "profile2", "tabTitle": "bar" } }, { "keys": ["ctrl+l"], "command": { "action": "newTab", "profile": "profile1", "tabTitle": "bar", "startingDirectory": "c:\\foo", "commandline":"foo.exe" } } ``` ## References This is a lot of work that was largely started in pursuit of #607. We want people to be able to override these properties straight from the commandline. While they may not make as much sense as keybindings like this, they'll make more sense as commandline arguments. ## PR Checklist * [x] Closes #998 * [x] I work here * [x] Tests added/passed * [x] Requires documentation to be updated ## Validation Steps Performed There are tests 🎉 Manually added some bindings, they opened the correct profiles in panes/tabs
2019-12-09 14:02:29 +01:00
// - newTerminalArgs: An object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
Add the ability to split a pane and put the new pane first. (#11145) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds directional modifiers for SplitState and convert those to the appropriate horizontal/vertical when splitting a pane. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #4340 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments "vertical" and "horizontal" splits were removed from `defaults.json`, but code was added to parse those as `right` and `down` respectively. It is also the case that if a user has a custom hotkey for `split: vertical` it will override the default for `split: right`. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Split the pane using each of the new directional movements
2021-09-15 22:14:57 +02:00
void TerminalPage::_SplitPane(const SplitDirection splitDirection,
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
const SplitType splitMode,
const float splitSize,
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
const NewTerminalArgs& newTerminalArgs)
{
const auto focusedTab{ _GetFocusedTabImpl() };
// Do nothing if no TerminalTab is focused
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
if (!focusedTab)
{
return;
}
Add the ability to split a pane and put the new pane first. (#11145) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds directional modifiers for SplitState and convert those to the appropriate horizontal/vertical when splitting a pane. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #4340 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments "vertical" and "horizontal" splits were removed from `defaults.json`, but code was added to parse those as `right` and `down` respectively. It is also the case that if a user has a custom hotkey for `split: vertical` it will override the default for `split: right`. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Split the pane using each of the new directional movements
2021-09-15 22:14:57 +02:00
_SplitPane(*focusedTab, splitDirection, splitMode, splitSize, newTerminalArgs);
Add Split Tab option to tab context menu (#10832) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds the Split Tab option to the tab context menu. Clicking this option will `auto` split the active pane of the tab into a duplicate pane. Clicking on an unfocused tab and splitting it will bring that tab into focus and split its active pane. We could make this a flyout from the context menu to let people choose horizontal/vertical split in the future if it's requested. I'm also wondering if this should be called Split Pane instead of Split Tab? <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #1912 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #5025 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments https://user-images.githubusercontent.com/48369326/127691919-aae4683a-212a-4525-a0eb-a61c877461ed.mp4 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2021-08-05 15:46:24 +02:00
}
// Method Description:
// - Split the focused pane of the given tab, either horizontally or vertically, and place the
// given TermControl into the newly created pane.
// Arguments:
// - tab: The tab that is going to be split.
Add the ability to split a pane and put the new pane first. (#11145) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds directional modifiers for SplitState and convert those to the appropriate horizontal/vertical when splitting a pane. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #4340 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments "vertical" and "horizontal" splits were removed from `defaults.json`, but code was added to parse those as `right` and `down` respectively. It is also the case that if a user has a custom hotkey for `split: vertical` it will override the default for `split: right`. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Split the pane using each of the new directional movements
2021-09-15 22:14:57 +02:00
// - splitDirection: one value from the TerminalApp::SplitDirection enum, indicating how the
Add Split Tab option to tab context menu (#10832) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds the Split Tab option to the tab context menu. Clicking this option will `auto` split the active pane of the tab into a duplicate pane. Clicking on an unfocused tab and splitting it will bring that tab into focus and split its active pane. We could make this a flyout from the context menu to let people choose horizontal/vertical split in the future if it's requested. I'm also wondering if this should be called Split Pane instead of Split Tab? <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #1912 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #5025 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments https://user-images.githubusercontent.com/48369326/127691919-aae4683a-212a-4525-a0eb-a61c877461ed.mp4 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2021-08-05 15:46:24 +02:00
// new pane should be split from its parent.
// - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane.
// - newTerminalArgs: An object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
void TerminalPage::_SplitPane(TerminalTab& tab,
Add the ability to split a pane and put the new pane first. (#11145) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds directional modifiers for SplitState and convert those to the appropriate horizontal/vertical when splitting a pane. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #4340 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments "vertical" and "horizontal" splits were removed from `defaults.json`, but code was added to parse those as `right` and `down` respectively. It is also the case that if a user has a custom hotkey for `split: vertical` it will override the default for `split: right`. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Split the pane using each of the new directional movements
2021-09-15 22:14:57 +02:00
const SplitDirection splitDirection,
Add Split Tab option to tab context menu (#10832) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds the Split Tab option to the tab context menu. Clicking this option will `auto` split the active pane of the tab into a duplicate pane. Clicking on an unfocused tab and splitting it will bring that tab into focus and split its active pane. We could make this a flyout from the context menu to let people choose horizontal/vertical split in the future if it's requested. I'm also wondering if this should be called Split Pane instead of Split Tab? <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #1912 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #5025 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments https://user-images.githubusercontent.com/48369326/127691919-aae4683a-212a-4525-a0eb-a61c877461ed.mp4 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2021-08-05 15:46:24 +02:00
const SplitType splitMode,
const float splitSize,
const NewTerminalArgs& newTerminalArgs)
{
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
try
{
TerminalSettingsCreateResult controlSettings{ nullptr };
Profile profile{ nullptr };
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
if (splitMode == SplitType::Duplicate)
{
profile = tab.GetFocusedProfile();
if (profile)
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
{
// TODO GH#5047 If we cache the NewTerminalArgs, we no longer need to do this.
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = TerminalSettings::CreateWithProfile(_settings, profile, *_bindings);
Add Split Tab option to tab context menu (#10832) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds the Split Tab option to the tab context menu. Clicking this option will `auto` split the active pane of the tab into a duplicate pane. Clicking on an unfocused tab and splitting it will bring that tab into focus and split its active pane. We could make this a flyout from the context menu to let people choose horizontal/vertical split in the future if it's requested. I'm also wondering if this should be called Split Pane instead of Split Tab? <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #1912 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #5025 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments https://user-images.githubusercontent.com/48369326/127691919-aae4683a-212a-4525-a0eb-a61c877461ed.mp4 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2021-08-05 15:46:24 +02:00
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
2021-01-11 19:01:38 +01:00
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
controlSettings.DefaultSettings().StartingDirectory(workingDirectory);
2021-01-11 19:01:38 +01:00
}
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
}
// TODO: GH#5047 - In the future, we should get the Profile of
// the focused pane, and use that to build a new instance of the
// settings so we can duplicate this tab/pane.
//
// Currently, if the profile doesn't exist anymore in our
// settings, we'll silently do nothing.
//
// In the future, it will be preferable to just duplicate the
// current control's settings, but we can't do that currently,
// because we won't be able to create a new instance of the
// connection without keeping an instance of the original Profile
// object around.
}
if (!profile)
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
{
profile = _settings.GetProfileForArgs(newTerminalArgs);
controlSettings = TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings);
}
const auto controlConnection = _CreateConnectionFromSettings(profile, controlSettings.DefaultSettings());
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
const float contentWidth = ::base::saturated_cast<float>(_tabContent.ActualWidth());
const float contentHeight = ::base::saturated_cast<float>(_tabContent.ActualHeight());
const winrt::Windows::Foundation::Size availableSpace{ contentWidth, contentHeight };
Add the ability to split a pane and put the new pane first. (#11145) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds directional modifiers for SplitState and convert those to the appropriate horizontal/vertical when splitting a pane. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #4340 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments "vertical" and "horizontal" splits were removed from `defaults.json`, but code was added to parse those as `right` and `down` respectively. It is also the case that if a user has a custom hotkey for `split: vertical` it will override the default for `split: right`. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Split the pane using each of the new directional movements
2021-09-15 22:14:57 +02:00
auto realSplitType = splitDirection;
if (realSplitType == SplitDirection::Automatic)
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
{
Add Split Tab option to tab context menu (#10832) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds the Split Tab option to the tab context menu. Clicking this option will `auto` split the active pane of the tab into a duplicate pane. Clicking on an unfocused tab and splitting it will bring that tab into focus and split its active pane. We could make this a flyout from the context menu to let people choose horizontal/vertical split in the future if it's requested. I'm also wondering if this should be called Split Pane instead of Split Tab? <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #1912 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #5025 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments https://user-images.githubusercontent.com/48369326/127691919-aae4683a-212a-4525-a0eb-a61c877461ed.mp4 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2021-08-05 15:46:24 +02:00
realSplitType = tab.PreCalculateAutoSplit(availableSpace);
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
}
Add Split Tab option to tab context menu (#10832) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds the Split Tab option to the tab context menu. Clicking this option will `auto` split the active pane of the tab into a duplicate pane. Clicking on an unfocused tab and splitting it will bring that tab into focus and split its active pane. We could make this a flyout from the context menu to let people choose horizontal/vertical split in the future if it's requested. I'm also wondering if this should be called Split Pane instead of Split Tab? <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #1912 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #5025 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments https://user-images.githubusercontent.com/48369326/127691919-aae4683a-212a-4525-a0eb-a61c877461ed.mp4 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2021-08-05 15:46:24 +02:00
const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
if (!canSplit)
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
{
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
return;
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
}
auto newControl = _InitControl(controlSettings, controlConnection);
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
// Hookup our event handlers to the new terminal
Move Pane to Tab (GH7075) (#10780) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed. This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #4587 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #7075 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Things done: - Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work. - Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls. - Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired. - Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early). - Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 . To do: - Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary. Next Steps: - In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI. - Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab). - Its been 10 years, I just really want to use concepts already. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 18:41:17 +02:00
_RegisterTerminalEvents(newControl);
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
_UnZoomIfNeeded();
tab.SplitPane(realSplitType, splitSize, profile, newControl);
Only focus the active pane once initialization is complete (#10978) ## Summary of the Pull Request Since the days immemorial of the Terminal, the TermControl has auto-focused itself when it finalizes its layout. This has led to the problem that `wt ; sp ; sp ; sp...` ends up focusing one of these panes at random. This PR fixes this issue by getting rid of the auto-focusing. Panes now manually get focused when created. We manually focus the active pane when a commandline is dispatched. since we're internally tracking "active" separate from "focused", this ends up working as you'd hope. ## References ## PR Checklist * [x] Closes #6586 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I also had to turn the cursor off by default. Most `TermControl`s would never get the `LostFocus` event, so their cursors would get left `On`, and that's not right. ## Validation Steps Performed I've run the following things a bunch of times to make sure they work: * `wtd sp ; sp ; sp` * `wtd sp ; sp ; sp ; fp -t 0` * `newTab` * `splitPane` * use the command palette to do the above as well Where the result used to be random (cases 1 & 2), the result is exactly what you'd expect now. It doesn't work at all for ``` wtd sp ; sp ; sp ; mf left ``` Presumably because we can't `move-focus` directionally during startup. However, that doesn't work _today_ either, so it's not making it worse. Just highlights that single scenario doesn't work right.
2021-08-24 11:49:45 +02:00
// After GH#6586, the control will no longer focus itself
// automatically when it's finished being laid out. Manually focus
// the control here instead.
if (_startupState == StartupState::Initialized)
{
if (const auto control = _GetActiveControl())
{
control.Focus(FocusState::Programmatic);
}
Only focus the active pane once initialization is complete (#10978) ## Summary of the Pull Request Since the days immemorial of the Terminal, the TermControl has auto-focused itself when it finalizes its layout. This has led to the problem that `wt ; sp ; sp ; sp...` ends up focusing one of these panes at random. This PR fixes this issue by getting rid of the auto-focusing. Panes now manually get focused when created. We manually focus the active pane when a commandline is dispatched. since we're internally tracking "active" separate from "focused", this ends up working as you'd hope. ## References ## PR Checklist * [x] Closes #6586 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I also had to turn the cursor off by default. Most `TermControl`s would never get the `LostFocus` event, so their cursors would get left `On`, and that's not right. ## Validation Steps Performed I've run the following things a bunch of times to make sure they work: * `wtd sp ; sp ; sp` * `wtd sp ; sp ; sp ; fp -t 0` * `newTab` * `splitPane` * use the command palette to do the above as well Where the result used to be random (cases 1 & 2), the result is exactly what you'd expect now. It doesn't work at all for ``` wtd sp ; sp ; sp ; mf left ``` Presumably because we can't `move-focus` directionally during startup. However, that doesn't work _today_ either, so it's not making it worse. Just highlights that single scenario doesn't work right.
2021-08-24 11:49:45 +02:00
}
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
}
CATCH_LOG();
}
Add the ability to toggle a pane's split direction (#10713) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Add the ability to toggle a pane's split direction - Switch from horizontal to vertical split (and vice versa) - Propogate new borders through to children. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #10665 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #10665 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Ran terminal, created multiple panes in different orientations, ran command through command palate and verified that they displayed properly in the new orientation.
2021-08-02 23:04:57 +02:00
// Method Description:
// - Switches the split orientation of the currently focused pane.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_ToggleSplitOrientation()
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
_UnZoomIfNeeded();
terminalTab->ToggleSplitOrientation();
}
}
// Method Description:
// - Attempt to move a separator between panes, as to resize each child on
// either size of the separator. See Pane::ResizePane for details.
// - Moves a separator on the currently focused tab.
// Arguments:
// - direction: The direction to move the separator in.
// Return Value:
// - <none>
void TerminalPage::_ResizePane(const ResizeDirection& direction)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
_UnZoomIfNeeded();
terminalTab->ResizePane(direction);
}
}
// Method Description:
// - Move the viewport of the terminal of the currently focused tab up or
// down a page. The page length will be dependent on the terminal view height.
// Arguments:
// - scrollDirection: ScrollUp will move the viewport up, ScrollDown will move the viewport down
void TerminalPage::_ScrollPage(ScrollDirection scrollDirection)
{
// Do nothing if for some reason, there's no terminal tab in focus. We don't want to crash.
if (const auto terminalTab{ _GetFocusedTabImpl() })
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
{
Hook up the keybindings to the SUI, redux (#10121) ## Summary of the Pull Request This is a redux of #8882. From the original: > This is really similar to what we're doing with the `CommandPalette`. We're adding a ~~Preview~~`KeyDown` handler to the SUI `MainPage`, that connects to `TerminalPage::_HandleKey`. That allows the SUI a chance to search the keymap to dispatch actions for keybindings, similar to how the command palette does it. > > This also means it's now possible for the SUI to invoke _all_ the actions available to the Terminal. This includes the ones like `IncreaseFontSize`, which require a _Terminal_ to actually do something. So we have to make sure all the calls to `_GetActiveControl` actually check that the result is non-null before using it. > > A bunch of the actions do nothing now from a SUI tab, others behave _weird_. Like "Rename tab" / "Open Tab Renamer" do nothing. "Duplicate Tab" again does nothing - we try making a new settings tab, which just focuses the settings tab again. "Copy text" definitely does nothing, same with paste. I don't know why I thought this wouldn't work. I thought we'd have to do this in `PreviewKeyDown` or something, which led to [weirdness](https://github.com/microsoft/terminal/pull/8882#issuecomment-767088554). Turns out, we don't need it to be in `PreviewKeyDown`. It can just be in the SUI's `KeyDown`. ## References * Original: #8882 * Workaround was in #8885 ## PR Checklist * [x] Closes #8767 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments The special case handler from #8885 is no longer needed ## Validation Steps Performed * Switching tabs with Ctrl+Tab works * Command palette works * fullscreen, focus mode works * close window works * copy paste on Ctrl+C/V works, even when bound * Select all text in textboxes works * tab navigation through UI elements works
2021-05-24 21:18:38 +02:00
if (const auto& control{ _GetActiveControl() })
{
const auto termHeight = control.ViewHeight();
auto scrollDelta = _ComputeScrollDelta(scrollDirection, termHeight);
terminalTab->Scroll(scrollDelta);
}
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
}
}
void TerminalPage::_ScrollToBufferEdge(ScrollDirection scrollDirection)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
auto scrollDelta = _ComputeScrollDelta(scrollDirection, INT_MAX);
terminalTab->Scroll(scrollDelta);
}
}
// Method Description:
// - Gets the title of the currently focused terminal control. If there
// isn't a control selected for any reason, returns "Windows Terminal"
// Arguments:
// - <none>
// Return Value:
// - the title of the focused control if there is one, else "Windows Terminal"
hstring TerminalPage::Title()
{
if (_settings.GlobalSettings().ShowTitleInTitlebar())
{
auto selectedIndex = _tabView.SelectedIndex();
if (selectedIndex >= 0)
{
try
{
Decouple "Active Terminal" and "Focused Control" (#3540) ## Summary of the Pull Request Unties the concept of "focused control" from "active control". Previously, we were exclusively using the "Focused" state of `TermControl`s to determine which one was active. This was fraught with gotchas - if anything else became focused, then suddenly there was _no_ pane focused in the Tab. This happened especially frequently if the user clicked on a tab to focus the window. Furthermore, in experimental branches with more UI added to the Terminal (such as [dev/migrie/f/2046-command-palette](https://github.com/microsoft/terminal/tree/dev/migrie/f/2046-command-palette)), when these UIs were added to the Terminal, they'd take focus, which again meant that there was no focused pane. This fixes these issue by having each Tab manually track which Pane is active in that tab. The Tab is now the arbiter of who in the tree is "active". Panes still track this state, for them to be able to MoveFocus appropriately. It also contains a related fix to prevent the tab separator from stealing focus from the TermControl. This required us to set the color of the un-focused Pane border to some color other that Transparent, so I went with the TabViewBackground. Panes now look like the following: ![image](https://user-images.githubusercontent.com/18356694/68697343-41ea2380-0544-11ea-8218-601b57fdd835.png) ## References See also: #2046 ## PR Checklist * [x] Closes #1205 * [x] Closes #522 * [x] Closes #999 * [x] I work here * [😢] Tests added/passed * [n/a] Requires documentation to be updated ## Validation Steps Performed Tested manually opening panes, closing panes, clicking around panes, the whole dance. --------------------------------------------------- * this is janky but is close for some reason? * This is _almost_ right to solve #1205 If I want to double up and also fix #522 (which I do), then I need to also * when a tab GetsFocus, send the focus instead to the Pane * When the border is clicked on, focus that pane's control And like a lot of cleanup, because this is horrifying * hey this autorevoker is really nice * Encapsulate Pane::pfnGotFocus * Propogate the events back up on close * Encapsulate Tab::pfnFocusChanged, and clean up TerminalPage a bit * Mostly just code cleanup, commenting * This works to hittest on the borders If the border is `Transparent`, then it can't hittest for Tapped events, and it'll fall through (to someone) THis at least works, but looks garish * Match the pane border to the TabViewHeader * Fix a bit of dead code and a bad copy-pasta * This _works_ to use a winrt event, but it's dirty * Clean up everything from the winrt::event debacle. * This is dead code that shouldn't have been there * Turn Tab's callback into a winrt::event as well
2019-11-18 22:41:25 +01:00
if (auto focusedControl{ _GetActiveControl() })
{
return focusedControl.Title();
}
}
CATCH_LOG();
}
}
return { L"Windows Terminal" };
}
// Method Description:
// - Handles the special case of providing a text override for the UI shortcut due to VK_OEM issue.
// Looks at the flags from the KeyChord modifiers and provides a concatenated string value of all
// in the same order that XAML would put them as well.
// Return Value:
// - a string representation of the key modifiers for the shortcut
//NOTE: This needs to be localized with https://github.com/microsoft/terminal/issues/794 if XAML framework issue not resolved before then
static std::wstring _FormatOverrideShortcutText(VirtualKeyModifiers modifiers)
{
std::wstring buffer{ L"" };
if (WI_IsFlagSet(modifiers, VirtualKeyModifiers::Control))
{
buffer += L"Ctrl+";
}
if (WI_IsFlagSet(modifiers, VirtualKeyModifiers::Shift))
{
buffer += L"Shift+";
}
if (WI_IsFlagSet(modifiers, VirtualKeyModifiers::Menu))
{
buffer += L"Alt+";
}
if (WI_IsFlagSet(modifiers, VirtualKeyModifiers::Windows))
{
buffer += L"Win+";
}
return buffer;
}
// Method Description:
// - Takes a MenuFlyoutItem and a corresponding KeyChord value and creates the accelerator for UI display.
// Takes into account a special case for an error condition for a comma
// Arguments:
// - MenuFlyoutItem that will be displayed, and a KeyChord to map an accelerator
void TerminalPage::_SetAcceleratorForMenuItem(WUX::Controls::MenuFlyoutItem& menuItem,
const KeyChord& keyChord)
{
#ifdef DEP_MICROSOFT_UI_XAML_708_FIXED
// work around https://github.com/microsoft/microsoft-ui-xaml/issues/708 in case of VK_OEM_COMMA
if (keyChord.Vkey() != VK_OEM_COMMA)
{
// use the XAML shortcut to give us the automatic capabilities
auto menuShortcut = Windows::UI::Xaml::Input::KeyboardAccelerator{};
// TODO: Modify this when https://github.com/microsoft/terminal/issues/877 is resolved
menuShortcut.Key(static_cast<Windows::System::VirtualKey>(keyChord.Vkey()));
// add the modifiers to the shortcut
menuShortcut.Modifiers(keyChord.Modifiers());
// add to the menu
menuItem.KeyboardAccelerators().Append(menuShortcut);
}
else // we've got a comma, so need to just use the alternate method
#endif
{
// extract the modifier and key to a nice format
auto overrideString = _FormatOverrideShortcutText(keyChord.Modifiers());
auto mappedCh = MapVirtualKeyW(keyChord.Vkey(), MAPVK_VK_TO_CHAR);
if (mappedCh != 0)
{
menuItem.KeyboardAcceleratorTextOverride(overrideString + gsl::narrow_cast<wchar_t>(mappedCh));
}
}
}
Snap to character grid when resizing window (#3181) When user resizes window, snap the size to align with the character grid (like e.g. putty, mintty and most unix terminals). Properly resolves arbitrary pane configuration (even with different font sizes and padding) trying to align each pane as close as possible. It also fixes terminal minimum size enforcement which was not quite well handled, especially with multiple panes. This PR does not however try to keep the terminals aligned at other user actions (e.g. font change or pane split). That is to be tracked by some other activity. Snapping is resolved in the pane tree, recursively, so it (hopefully) works for any possible layout. Along the way I had to clean up some things as so to make the resulting code not so cumbersome: 1. Pane.cpp: Replaced _firstPercent and _secondPercent with single _desiredSplitPosition to reduce invariants - these had to be kept in sync so their sum always gives 1 (and were not really a percent). The desired part refers to fact that since panes are aligned, there is usually some deviation from that ratio. 2. Pane.cpp: Fixed _GetMinSize() - it was improperly accounting for split direction 3. TerminalControl: Made dedicated member for padding instead of reading it from a control itself. This is because the winrt property functions turned out to be slow and this algorithm needs to access it many times. I also cached scrollbar width for the same reason. 4. AppHost: Moved window to client size resolution to virtual method, where IslandWindow and NonClientIslandWindow have their own implementations (as opposite to pointer casting). One problem with current implementation is I had to make a long call chain from the window that requests snapping to the (root) pane that implements it: IslandWindow -> AppHost's callback -> App -> TerminalPage -> Tab -> Pane. I don't know if this can be done better. ## Validation Steps Performed Spam split pane buttons, randomly change font sizes with ctrl+mouse wheel and drag the window back and forth. Closes #2834 Closes #2277
2020-01-08 22:19:23 +01:00
// Method Description:
// - Calculates the appropriate size to snap to in the given direction, for
// the given dimension. If the global setting `snapToGridOnResize` is set
// to `false`, this will just immediately return the provided dimension,
// effectively disabling snapping.
Snap to character grid when resizing window (#3181) When user resizes window, snap the size to align with the character grid (like e.g. putty, mintty and most unix terminals). Properly resolves arbitrary pane configuration (even with different font sizes and padding) trying to align each pane as close as possible. It also fixes terminal minimum size enforcement which was not quite well handled, especially with multiple panes. This PR does not however try to keep the terminals aligned at other user actions (e.g. font change or pane split). That is to be tracked by some other activity. Snapping is resolved in the pane tree, recursively, so it (hopefully) works for any possible layout. Along the way I had to clean up some things as so to make the resulting code not so cumbersome: 1. Pane.cpp: Replaced _firstPercent and _secondPercent with single _desiredSplitPosition to reduce invariants - these had to be kept in sync so their sum always gives 1 (and were not really a percent). The desired part refers to fact that since panes are aligned, there is usually some deviation from that ratio. 2. Pane.cpp: Fixed _GetMinSize() - it was improperly accounting for split direction 3. TerminalControl: Made dedicated member for padding instead of reading it from a control itself. This is because the winrt property functions turned out to be slow and this algorithm needs to access it many times. I also cached scrollbar width for the same reason. 4. AppHost: Moved window to client size resolution to virtual method, where IslandWindow and NonClientIslandWindow have their own implementations (as opposite to pointer casting). One problem with current implementation is I had to make a long call chain from the window that requests snapping to the (root) pane that implements it: IslandWindow -> AppHost's callback -> App -> TerminalPage -> Tab -> Pane. I don't know if this can be done better. ## Validation Steps Performed Spam split pane buttons, randomly change font sizes with ctrl+mouse wheel and drag the window back and forth. Closes #2834 Closes #2277
2020-01-08 22:19:23 +01:00
// - See Pane::CalcSnappedDimension
float TerminalPage::CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
{
if (_settings && _settings.GlobalSettings().SnapToGridOnResize())
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
return terminalTab->CalcSnappedDimension(widthOrHeight, dimension);
}
}
return dimension;
Snap to character grid when resizing window (#3181) When user resizes window, snap the size to align with the character grid (like e.g. putty, mintty and most unix terminals). Properly resolves arbitrary pane configuration (even with different font sizes and padding) trying to align each pane as close as possible. It also fixes terminal minimum size enforcement which was not quite well handled, especially with multiple panes. This PR does not however try to keep the terminals aligned at other user actions (e.g. font change or pane split). That is to be tracked by some other activity. Snapping is resolved in the pane tree, recursively, so it (hopefully) works for any possible layout. Along the way I had to clean up some things as so to make the resulting code not so cumbersome: 1. Pane.cpp: Replaced _firstPercent and _secondPercent with single _desiredSplitPosition to reduce invariants - these had to be kept in sync so their sum always gives 1 (and were not really a percent). The desired part refers to fact that since panes are aligned, there is usually some deviation from that ratio. 2. Pane.cpp: Fixed _GetMinSize() - it was improperly accounting for split direction 3. TerminalControl: Made dedicated member for padding instead of reading it from a control itself. This is because the winrt property functions turned out to be slow and this algorithm needs to access it many times. I also cached scrollbar width for the same reason. 4. AppHost: Moved window to client size resolution to virtual method, where IslandWindow and NonClientIslandWindow have their own implementations (as opposite to pointer casting). One problem with current implementation is I had to make a long call chain from the window that requests snapping to the (root) pane that implements it: IslandWindow -> AppHost's callback -> App -> TerminalPage -> Tab -> Pane. I don't know if this can be done better. ## Validation Steps Performed Spam split pane buttons, randomly change font sizes with ctrl+mouse wheel and drag the window back and forth. Closes #2834 Closes #2277
2020-01-08 22:19:23 +01:00
}
// Method Description:
// - Place `copiedData` into the clipboard as text. Triggered when a
// terminal control raises it's CopyToClipboard event.
// Arguments:
// - copiedData: the new string content to place on the clipboard.
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
winrt::fire_and_forget TerminalPage::_CopyToClipboardHandler(const IInspectable /*sender*/,
const CopyToClipboardEventArgs copiedData)
{
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::High);
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
DataPackage dataPack = DataPackage();
dataPack.RequestedOperation(DataPackageOperation::Copy);
// The EventArgs.Formats() is an override for the global setting "copyFormatting"
// iff it is set
bool useGlobal = copiedData.Formats() == nullptr;
auto copyFormats = useGlobal ?
_settings.GlobalSettings().CopyFormatting() :
copiedData.Formats().Value();
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
// copy text to dataPack
dataPack.SetText(copiedData.Text());
if (WI_IsFlagSet(copyFormats, CopyFormat::HTML))
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
{
// copy html to dataPack
const auto htmlData = copiedData.Html();
if (!htmlData.empty())
{
dataPack.SetHtmlFormat(htmlData);
}
}
Copy RTF data to the clipboard (#3535) ## Summary of the Pull Request RTF data is now copied to the clipboard. Tested by copy pasting text from terminal to WordPad. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #2487 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #2487 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Mostly similar to PR #1224. Added a new static method `GenRTF` in `TextBuffer` that is responsible for generating the RTF representation of a given text. The generated RTF is added to the `DataPackage` that is ultimately passed to the clipboard. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Validated by copy pasting text from the terminal to WordPad. Validated with different colors to make sure that is working. (MS Word seems to prefer HTML data from the clipboard instead of RTF.) <hr> * Copy RTF data to the clipboard * Added comment explaining various parts of the header * Fixed static code analysis issues and added noexcept to GenRTF() * Removed noexcept
2019-11-13 21:13:22 +01:00
if (WI_IsFlagSet(copyFormats, CopyFormat::RTF))
{
// copy rtf data to dataPack
const auto rtfData = copiedData.Rtf();
if (!rtfData.empty())
{
dataPack.SetRtf(rtfData);
}
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
}
try
{
Clipboard::SetContent(dataPack);
Clipboard::Flush();
}
CATCH_LOG();
}
// Function Description:
// - This function is called when the `TermControl` requests that we send
// it the clipboard's content.
// - Retrieves the data from the Windows Clipboard and converts it to text.
// - Shows warnings if the clipboard is too big or contains multiple lines
// of text.
// - Sends the text back to the TermControl through the event's
// `HandleClipboardData` member function.
// - Does some of this in a background thread, as to not hang/crash the UI thread.
// Arguments:
// - eventArgs: the PasteFromClipboard event sent from the TermControl
fire_and_forget TerminalPage::_PasteFromClipboardHandler(const IInspectable /*sender*/,
const PasteFromClipboardEventArgs eventArgs)
{
const DataPackageView data = Clipboard::GetContent();
// This will switch the execution of the function to a background (not
// UI) thread. This is IMPORTANT, because the getting the clipboard data
// will crash on the UI thread, because the main thread is a STA.
co_await winrt::resume_background();
try
{
hstring text = L"";
if (data.Contains(StandardDataFormats::Text()))
{
text = co_await data.GetTextAsync();
}
// Windows Explorer's "Copy address" menu item stores a StorageItem in the clipboard, and no text.
else if (data.Contains(StandardDataFormats::StorageItems()))
{
Windows::Foundation::Collections::IVectorView<Windows::Storage::IStorageItem> items = co_await data.GetStorageItemsAsync();
if (items.Size() > 0)
{
Windows::Storage::IStorageItem item = items.GetAt(0);
text = item.Path();
}
}
2021-10-28 17:38:23 +02:00
if (_settings.GlobalSettings().TrimPaste())
{
std::wstring_view textView{ text };
const auto pos = textView.find_last_not_of(L"\t\n\v\f\r ");
if (pos == textView.npos)
{
// Text is all white space, nothing to paste
co_return;
}
else if (const auto toRemove = textView.size() - 1 - pos; toRemove > 0)
{
textView.remove_suffix(toRemove);
text = { textView };
}
}
bool warnMultiLine = _settings.GlobalSettings().WarnAboutMultiLinePaste();
if (warnMultiLine)
{
const auto isNewLineLambda = [](auto c) { return c == L'\n' || c == L'\r'; };
const auto hasNewLine = std::find_if(text.cbegin(), text.cend(), isNewLineLambda) != text.cend();
warnMultiLine = hasNewLine;
}
constexpr const std::size_t minimumSizeForWarning = 1024 * 5; // 5 KiB
const bool warnLargeText = text.size() > minimumSizeForWarning &&
_settings.GlobalSettings().WarnAboutLargePaste();
if (warnMultiLine || warnLargeText)
{
co_await winrt::resume_foreground(Dispatcher());
if (warnMultiLine)
{
const auto focusedTab = _GetFocusedTabImpl();
// Do not warn about multi line pasting if the current tab has bracketed paste enabled.
warnMultiLine = warnMultiLine && !focusedTab->GetActiveTerminalControl().BracketedPasteEnabled();
}
// We have to initialize the dialog here to be able to change the text of the text block within it
FindName(L"MultiLinePasteDialog").try_as<WUX::Controls::ContentDialog>();
ClipboardText().Text(text);
// The vertical offset on the scrollbar does not reset automatically, so reset it manually
ClipboardContentScrollViewer().ScrollToVerticalOffset(0);
ContentDialogResult warningResult = ContentDialogResult::Primary;
if (warnMultiLine)
{
warningResult = co_await _ShowMultiLinePasteWarningDialog();
}
else if (warnLargeText)
{
warningResult = co_await _ShowLargePasteWarningDialog();
}
// Clear the clipboard text so it doesn't lie around in memory
ClipboardText().Text(L"");
if (warningResult != ContentDialogResult::Primary)
{
// user rejected the paste
co_return;
}
}
eventArgs.HandleClipboardData(text);
}
CATCH_LOG();
}
Rename `Microsoft.Terminal.TerminalControl` to `.Control`; Split into dll & lib (#9472) **BE NOT AFRAID**. I know that there's 107 files in this PR, but almost all of it is just find/replacing `TerminalControl` with `Control`. This is the start of the work to move TermControl into multiple pieces, for #5000. The PR starts this work by: * Splits `TerminalControl` into separate lib and dll projects. We'll want control tests in the future, and for that, we'll need a lib. * Moves `ICoreSettings` back into the `Microsoft.Terminal.Core` namespace. We'll have other types in there soon too. * I could not tell you why this works suddenly. New VS versions? New cppwinrt version? Maybe we're just better at dealing with mdmerge bugs these days. * RENAMES `Microsoft.Terminal.TerminalControl` to `Microsoft.Terminal.Control`. This touches pretty much every file in the sln. Sorry about that (not sorry). An upcoming PR will move much of the logic in TermControl into a new `ControlCore` class that we'll add in `Microsoft.Terminal.Core`. `ControlCore` will then be unittest-able in the `UnitTests_TerminalCore`, which will help prevent regressions like #9455 ## Detailed Description of the Pull Request / Additional comments You're really gonna want to clean the sln first, then merge this into your branch, then rebuild. It's very likely that old winmds will get left behind. If you see something like ``` Error MDM2007 Cannot create type Microsoft.Terminal.TerminalControl.KeyModifiers in read-only metadata file Microsoft.Terminal.TerminalControl. ``` then that's what happened to you.
2021-03-17 21:47:24 +01:00
void TerminalPage::_OpenHyperlinkHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::OpenHyperlinkEventArgs eventArgs)
OSC 8 support for conhost and terminal (#7251) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Conhost can now support OSC8 sequences (as specified [here](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)). Terminal also supports those sequences and additionally hyperlinks can be opened by Ctrl+LeftClicking on them. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #204 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [X] Closes #204 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Added support to: - parse OSC8 sequences and extract URIs from them (conhost and terminal) - add hyperlink uri data to textbuffer/screeninformation, associated with a hyperlink id (conhost and terminal) - attach hyperlink ids to text to allow for uri extraction from the textbuffer/screeninformation (conhost and terminal) - process ctrl+leftclick to open a hyperlink in the clicked region if present <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Open up a PowerShell tab and type ```PowerShell ${ESC}=[char]27 Write-Host "${ESC}]8;;https://github.com/microsoft/terminal${ESC}\This is a link!${ESC}]8;;${ESC}\" ``` Ctrl+LeftClick on the link correctly brings you to the terminal page on github ![hyperlink](https://user-images.githubusercontent.com/26824113/89953536-45a6f580-dbfd-11ea-8e0d-8a3cd25c634a.gif)
2020-09-03 19:52:39 +02:00
{
try
{
auto parsed = winrt::Windows::Foundation::Uri(eventArgs.Uri().c_str());
if (_IsUriSupported(parsed))
OSC 8 support for conhost and terminal (#7251) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Conhost can now support OSC8 sequences (as specified [here](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)). Terminal also supports those sequences and additionally hyperlinks can be opened by Ctrl+LeftClicking on them. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #204 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [X] Closes #204 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Added support to: - parse OSC8 sequences and extract URIs from them (conhost and terminal) - add hyperlink uri data to textbuffer/screeninformation, associated with a hyperlink id (conhost and terminal) - attach hyperlink ids to text to allow for uri extraction from the textbuffer/screeninformation (conhost and terminal) - process ctrl+leftclick to open a hyperlink in the clicked region if present <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Open up a PowerShell tab and type ```PowerShell ${ESC}=[char]27 Write-Host "${ESC}]8;;https://github.com/microsoft/terminal${ESC}\This is a link!${ESC}]8;;${ESC}\" ``` Ctrl+LeftClick on the link correctly brings you to the terminal page on github ![hyperlink](https://user-images.githubusercontent.com/26824113/89953536-45a6f580-dbfd-11ea-8e0d-8a3cd25c634a.gif)
2020-09-03 19:52:39 +02:00
{
ShellExecute(nullptr, L"open", eventArgs.Uri().c_str(), nullptr, nullptr, SW_SHOWNORMAL);
}
else
{
_ShowCouldNotOpenDialog(RS_(L"UnsupportedSchemeText"), eventArgs.Uri());
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
_ShowCouldNotOpenDialog(RS_(L"InvalidUriText"), eventArgs.Uri());
}
}
// Method Description:
// - Opens up a dialog box explaining why we could not open a URI
// Arguments:
// - The reason (unsupported scheme, invalid uri, potentially more in the future)
// - The uri
void TerminalPage::_ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri)
{
if (auto presenter{ _dialogPresenter.get() })
{
// FindName needs to be called first to actually load the xaml object
auto unopenedUriDialog = FindName(L"CouldNotOpenUriDialog").try_as<WUX::Controls::ContentDialog>();
// Insert the reason and the URI
CouldNotOpenUriReason().Text(reason);
UnopenedUri().Text(uri);
// Show the dialog
presenter.ShowDialog(unopenedUriDialog);
OSC 8 support for conhost and terminal (#7251) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Conhost can now support OSC8 sequences (as specified [here](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)). Terminal also supports those sequences and additionally hyperlinks can be opened by Ctrl+LeftClicking on them. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References #204 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [X] Closes #204 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Added support to: - parse OSC8 sequences and extract URIs from them (conhost and terminal) - add hyperlink uri data to textbuffer/screeninformation, associated with a hyperlink id (conhost and terminal) - attach hyperlink ids to text to allow for uri extraction from the textbuffer/screeninformation (conhost and terminal) - process ctrl+leftclick to open a hyperlink in the clicked region if present <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Open up a PowerShell tab and type ```PowerShell ${ESC}=[char]27 Write-Host "${ESC}]8;;https://github.com/microsoft/terminal${ESC}\This is a link!${ESC}]8;;${ESC}\" ``` Ctrl+LeftClick on the link correctly brings you to the terminal page on github ![hyperlink](https://user-images.githubusercontent.com/26824113/89953536-45a6f580-dbfd-11ea-8e0d-8a3cd25c634a.gif)
2020-09-03 19:52:39 +02:00
}
}
// Method Description:
// - Determines if the given URI is currently supported
// Arguments:
// - The parsed URI
// Return value:
// - True if we support it, false otherwise
bool TerminalPage::_IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri)
{
if (parsedUri.SchemeName() == L"http" || parsedUri.SchemeName() == L"https")
{
return true;
}
if (parsedUri.SchemeName() == L"file")
{
const auto host = parsedUri.Host();
// If no hostname was provided or if the hostname was "localhost", Host() will return an empty string
// and we allow it
if (host == L"")
{
return true;
}
// TODO: by the OSC 8 spec, if a hostname (other than localhost) is provided, we _should_ be
// comparing that value against what is returned by GetComputerNameExW and making sure they match.
// However, ShellExecute does not seem to be happy with file URIs of the form
// file://{hostname}/path/to/file.ext
// and so while we could do the hostname matching, we do not know how to actually open the URI
// if its given in that form. So for now we ignore all hostnames other than localhost
}
return false;
}
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
// Important! Don't take this eventArgs by reference, we need to extend the
// lifetime of it to the other side of the co_await!
winrt::fire_and_forget TerminalPage::_ControlNoticeRaisedHandler(const IInspectable /*sender*/,
const Microsoft::Terminal::Control::NoticeEventArgs eventArgs)
{
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
auto weakThis = get_weak();
co_await winrt::resume_foreground(Dispatcher());
if (auto page = weakThis.get())
{
winrt::hstring message = eventArgs.Message();
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
winrt::hstring title;
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
switch (eventArgs.Level())
{
case NoticeLevel::Debug:
title = RS_(L"NoticeDebug"); //\xebe8
break;
case NoticeLevel::Info:
title = RS_(L"NoticeInfo"); // \xe946
break;
case NoticeLevel::Warning:
title = RS_(L"NoticeWarning"); //\xe7ba
break;
case NoticeLevel::Error:
title = RS_(L"NoticeError"); //\xe783
break;
}
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
page->_ShowControlNoticeDialog(title, message);
}
}
void TerminalPage::_ShowControlNoticeDialog(const winrt::hstring& title, const winrt::hstring& message)
{
if (auto presenter{ _dialogPresenter.get() })
{
// FindName needs to be called first to actually load the xaml object
auto controlNoticeDialog = FindName(L"ControlNoticeDialog").try_as<WUX::Controls::ContentDialog>();
ControlNoticeDialog().Title(winrt::box_value(title));
// Insert the message
NoticeMessage().Text(message);
// Show the dialog
presenter.ShowDialog(controlNoticeDialog);
}
}
// Method Description:
// - Copy text from the focused terminal to the Windows Clipboard
// Arguments:
// - singleLine: if enabled, copy contents as a single line of text
// - formats: dictate which formats need to be copied
// Return Value:
// - true iff we we able to copy text (if a selection was active)
bool TerminalPage::_CopyText(const bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats)
{
Hook up the keybindings to the SUI, redux (#10121) ## Summary of the Pull Request This is a redux of #8882. From the original: > This is really similar to what we're doing with the `CommandPalette`. We're adding a ~~Preview~~`KeyDown` handler to the SUI `MainPage`, that connects to `TerminalPage::_HandleKey`. That allows the SUI a chance to search the keymap to dispatch actions for keybindings, similar to how the command palette does it. > > This also means it's now possible for the SUI to invoke _all_ the actions available to the Terminal. This includes the ones like `IncreaseFontSize`, which require a _Terminal_ to actually do something. So we have to make sure all the calls to `_GetActiveControl` actually check that the result is non-null before using it. > > A bunch of the actions do nothing now from a SUI tab, others behave _weird_. Like "Rename tab" / "Open Tab Renamer" do nothing. "Duplicate Tab" again does nothing - we try making a new settings tab, which just focuses the settings tab again. "Copy text" definitely does nothing, same with paste. I don't know why I thought this wouldn't work. I thought we'd have to do this in `PreviewKeyDown` or something, which led to [weirdness](https://github.com/microsoft/terminal/pull/8882#issuecomment-767088554). Turns out, we don't need it to be in `PreviewKeyDown`. It can just be in the SUI's `KeyDown`. ## References * Original: #8882 * Workaround was in #8885 ## PR Checklist * [x] Closes #8767 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments The special case handler from #8885 is no longer needed ## Validation Steps Performed * Switching tabs with Ctrl+Tab works * Command palette works * fullscreen, focus mode works * close window works * copy paste on Ctrl+C/V works, even when bound * Select all text in textboxes works * tab navigation through UI elements works
2021-05-24 21:18:38 +02:00
if (const auto& control{ _GetActiveControl() })
{
return control.CopySelectionToClipboard(singleLine, formats);
}
return false;
}
// Method Description:
// - Send an event (which will be caught by AppHost) to set the progress indicator on the taskbar
// Arguments:
// - sender (not used)
// - eventArgs: the arguments specifying how to set the progress indicator
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
winrt::fire_and_forget TerminalPage::_SetTaskbarProgressHandler(const IInspectable /*sender*/, const IInspectable /*eventArgs*/)
{
Split `TermControl` into a Core, Interactivity, and Control layer (#9820) ## Summary of the Pull Request Brace yourselves, it's finally here. This PR does the dirty work of splitting the monolithic `TermControl` into three components. These components are: * `ControlCore`: This encapsulates the `Terminal` instance, the `DxEngine` and `Renderer`, and the `Connection`. This is intended to everything that someone might need to stand up a terminal instance in a control, but without any regard for how the UX works. * `ControlInteractivity`: This is a wrapper for the `ControlCore`, which holds the logic for things like double-click, right click copy/paste, selection, etc. This is intended to be a UI framework-independent abstraction. The methods this layer exposes can be called the same from both the WinUI TermControl and the WPF control. * `TermControl`: This is the UWP control. It's got a Core and Interactivity inside it, which it uses for the actual logic of the terminal itself. TermControl's main responsibility is now By splitting into smaller pieces, it will enable us to * write unit tests for the `Core` and `Interactivity` bits, which we desparately need * Combine `ControlCore` and `ControlInteractivity` in an out-of-proc core process in the future, to enable tab tearout. However, we're not doing that work quite yet. There's still lots of work to be done to enable that, thought this is likely the biggest portion. Ideally, this would just be methods moved wholesale from one file to another. Unfortunately, there are a bunch of cases where that didn't work as well as expected. Especially when trying to better enforce the boundary between the classes. We've got a couple tests here that I've added. These are partially examples, and partially things I ran into while implementing this. A bunch of things from #7001 can go in now that we have this. This PR is gonna be a huge pain to review - 38 files with 3,730 additions and 1,661 deletions is nothing to scoff at. It will also conflict 100% with anything that's targeting `TermControl`. I'm hoping we can review this over the course of the next week and just be done with it, and leave plenty of runway for 1.9 bugs in post. ## References * In pursuit of #1256 * Proc Model: #5000 * https://github.com/microsoft/terminal/projects/5 ## PR Checklist * [x] Closes #6842 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760249 * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50760258 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments * I don't love the names `ControlCore` and `ControlInteractivity`. Open to other names. * I added a `ICoreState` interface for "properties that come from the `ControlCore`, but consumers of the `TermControl` need to know". In the future, these will all need to be handled specially, because they might involve an RPC call to retrieve the info from the core (or cache it) in the window process. * I've added more `EventArgs` to make more events proper `TypedEvent`s. * I've changed how the TerminalApp layer requests updated TaskbarProgress state. It doesn't need to pump TermControl to raise a new event anymore. * ~~Something that snuck into this branch in the very long history is the switch to `DCompositionCreateSurfaceHandle` for the `DxEngine`. @miniksa wrote this originally in 30b8335, I'm just finally committing it here. We'll need that in the future for the out-of-proc stuff.~~ * I reverted this in c113b65d9. We can revert _that_ commit when we want to come back to it. * I've changed the acrylic handler a decent amount. But added tests! * All the `ThrottledFunc` things are left in `TermControl`. Some might be able to move down into core/interactivity, but once we figure out how to use a different kind of Dispatcher (because a UI thread won't necessarily exist for those components). * I've undoubtably messed up the merging of the locking around the appearance config stuff recently ## Validation Steps Performed I've got a rolling list in https://github.com/microsoft/terminal/issues/6842#issuecomment-810990460 that I'm updating as I go.
2021-04-27 17:50:45 +02:00
co_await resume_foreground(Dispatcher());
_SetTaskbarProgressHandlers(*this, nullptr);
}
// Method Description:
// - Paste text from the Windows Clipboard to the focused terminal
void TerminalPage::_PasteText()
{
Hook up the keybindings to the SUI, redux (#10121) ## Summary of the Pull Request This is a redux of #8882. From the original: > This is really similar to what we're doing with the `CommandPalette`. We're adding a ~~Preview~~`KeyDown` handler to the SUI `MainPage`, that connects to `TerminalPage::_HandleKey`. That allows the SUI a chance to search the keymap to dispatch actions for keybindings, similar to how the command palette does it. > > This also means it's now possible for the SUI to invoke _all_ the actions available to the Terminal. This includes the ones like `IncreaseFontSize`, which require a _Terminal_ to actually do something. So we have to make sure all the calls to `_GetActiveControl` actually check that the result is non-null before using it. > > A bunch of the actions do nothing now from a SUI tab, others behave _weird_. Like "Rename tab" / "Open Tab Renamer" do nothing. "Duplicate Tab" again does nothing - we try making a new settings tab, which just focuses the settings tab again. "Copy text" definitely does nothing, same with paste. I don't know why I thought this wouldn't work. I thought we'd have to do this in `PreviewKeyDown` or something, which led to [weirdness](https://github.com/microsoft/terminal/pull/8882#issuecomment-767088554). Turns out, we don't need it to be in `PreviewKeyDown`. It can just be in the SUI's `KeyDown`. ## References * Original: #8882 * Workaround was in #8885 ## PR Checklist * [x] Closes #8767 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments The special case handler from #8885 is no longer needed ## Validation Steps Performed * Switching tabs with Ctrl+Tab works * Command palette works * fullscreen, focus mode works * close window works * copy paste on Ctrl+C/V works, even when bound * Select all text in textboxes works * tab navigation through UI elements works
2021-05-24 21:18:38 +02:00
if (const auto& control{ _GetActiveControl() })
{
control.PasteTextFromClipboard();
}
}
// Function Description:
// - Called when the settings button is clicked. ShellExecutes the settings
// file, as to open it in the default editor for .json files. Does this in
// a background thread, as to not hang/crash the UI thread.
fire_and_forget TerminalPage::_LaunchSettings(const SettingsTarget target)
{
if (target == SettingsTarget::SettingsUI)
{
_OpenSettingsUI();
}
else
{
// This will switch the execution of the function to a background (not
// UI) thread. This is IMPORTANT, because the Windows.Storage API's
// (used for retrieving the path to the file) will crash on the UI
// thread, because the main thread is a STA.
co_await winrt::resume_background();
auto openFile = [](const auto& filePath) {
HINSTANCE res = ShellExecute(nullptr, nullptr, filePath.c_str(), nullptr, nullptr, SW_SHOW);
if (static_cast<int>(reinterpret_cast<uintptr_t>(res)) <= 32)
{
ShellExecute(nullptr, nullptr, L"notepad", filePath.c_str(), nullptr, SW_SHOW);
}
};
switch (target)
{
case SettingsTarget::DefaultsFile:
openFile(CascadiaSettings::DefaultSettingsPath());
break;
case SettingsTarget::SettingsFile:
openFile(CascadiaSettings::SettingsPath());
break;
case SettingsTarget::AllFiles:
openFile(CascadiaSettings::DefaultSettingsPath());
openFile(CascadiaSettings::SettingsPath());
break;
}
}
}
// Method Description:
// - Called when our tab content size changes. This updates each tab with
// the new size, so they have a chance to update each of their panes with
// the new size.
// Arguments:
// - e: the SizeChangedEventArgs with the new size of the tab content area.
// Return Value:
// - <none>
void TerminalPage::_OnContentSizeChanged(const IInspectable& /*sender*/, Windows::UI::Xaml::SizeChangedEventArgs const& e)
{
const auto newSize = e.NewSize();
minor refactor: Move Tab management into its own file (#9629) I think we can all agree that `TerminalPage.cpp` is an unruly beast of a file. It's got everything. It does everything. It can sometimes be a bit hard to work with, because of simply how big it is. This PR tries to alleviate this by making `TerminalPage.cpp` just a little smaller. It does so by moving pretty much everything related to tab management into its own file, `TabManagement.cpp`. These methods that have moved are all the same as they were before, and they're still members of `TerminalPage`. But now they're all in one place. I tried to move all the references to `_tabs` in `TerminalPage.cpp`, but there's still a few that I left behind. Mostly because I felt that moving those would be too gnarly a code change for an otherwise simple cut&paste PR. There are a few new methods I introduced: * `_TabDragStarted` and `_TabDragCompleted`: These were lambdas before, promoted to full methods. * `_DismissTabContextMenus`: Remove all the right-click context menus from the tabs * `_FocusCurrentTab`: This one's a bit trickier, we were actually doing this in a few different places, so I tried consolidating. * `_HasMultipleTabs`: This doesn't need explaining. * `_RemoveAllTabs`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` * `_ResizeTabContent`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` In the future, some enterprising young soul could try promoting that file to its own class, and hiding `_tabs` (and `_mruTabs`) inside it. Probably would need to take a reference to TerminalPage's `_tabView` and `_newTabButton`. I'm not doing that right now, because I already hate the idea of the ... > 920 additions and 847 deletions. ... I'm making you look at already. ## Other thoughts Some of the calls might be a little arbitrary - `_OpenNewTab` and `_CreateNewTabFromSettings` probably should stay in `TerminalPage`? Or at least elements of those might need to get split up better. Similarly `TerminalPage::_OpenSettingsUI` stayed in `TerminalPage.cpp`, but it does a lot of the same work as `_CreateNewTabFromSettings`. I'm not saying this is the definitive places for these methods - it's code we're working with, not stone ☺️
2021-03-29 21:53:39 +02:00
_ResizeTabContent(newSize);
}
// Method Description:
// - Responds to the TabView control's Tab Closing event by removing
// the indicated tab from the set and focusing another one.
// The event is cancelled so App maintains control over the
// items in the tabview.
// Arguments:
// - sender: the control that originated this event
// - eventArgs: the event's constituent arguments
void TerminalPage::_OnTabCloseRequested(const IInspectable& /*sender*/, const MUX::Controls::TabViewTabCloseRequestedEventArgs& eventArgs)
{
const auto tabViewItem = eventArgs.Tab();
if (auto tab{ _GetTabByTabViewItem(tabViewItem) })
{
_HandleCloseTabRequested(tab);
}
}
TermControl TerminalPage::_InitControl(const TerminalSettingsCreateResult& settings, const ITerminalConnection& connection)
{
// Give term control a child of the settings so that any overrides go in the child
// This way, when we do a settings reload we just update the parent and the overrides remain
const auto child = TerminalSettings::CreateWithParent(settings);
TermControl term{ child.DefaultSettings(), connection };
term.UnfocusedAppearance(child.UnfocusedSettings()); // It is okay for the unfocused settings to be null
return term;
}
// Method Description:
// - Hook up keybindings, and refresh the UI of the terminal.
// This includes update the settings of all the tabs according
// to their profiles, update the title and icon of each tab, and
// finally create the tab flyout
void TerminalPage::_RefreshUIForSettingsReload()
{
// Re-wire the keybindings to their handlers, as we'll have created a
// new AppKeyBindings object.
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
_HookupKeyBindings(_settings.ActionMap());
// Refresh UI elements
// Mapping by GUID isn't _excellent_ because the defaults profile doesn't have a stable GUID; however,
// when we stabilize its guid this will become fully safe.
std::unordered_map<winrt::guid, std::pair<Profile, TerminalSettingsCreateResult>> profileGuidSettingsMap;
const auto profileDefaults{ _settings.ProfileDefaults() };
const auto allProfiles{ _settings.AllProfiles() };
profileGuidSettingsMap.reserve(allProfiles.Size() + 1);
// Include the Defaults profile for consideration
profileGuidSettingsMap.insert_or_assign(profileDefaults.Guid(), std::pair{ profileDefaults, nullptr });
for (const auto& newProfile : allProfiles)
{
// Avoid creating a TerminalSettings right now. They're not totally cheap, and we suspect that users with many
// panes may not be using all of their profiles at the same time. Lazy evaluation is king!
profileGuidSettingsMap.insert_or_assign(newProfile.Guid(), std::pair{ newProfile, nullptr });
}
for (const auto& tab : _tabs)
{
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
{
terminalTab->UpdateSettings();
Process actions sync. on startup; don't dupe nonexistent profile (#5090) This PR has evolved to encapsulate two related fixes that I can't really untie anymore. #2455 - Duplicating a tab that doesn't exist anymore This was the bug I was originally fixing in #4429. When the user tries to `duplicateTab` with a profile that doesn't exist anymore (like might happen after a settings reload), don't crash. As I was going about adding tests for this, got blocked by the fact that the Terminal couldn't open _any_ panes while the `TerminalPage` was size 0x0. This had two theoretical solutions: * Fake the `TerminalPage` into thinking it had a real size in the test - probably possible, though I'm unsure how it would work in practice. * Change `Pane`s to not require an `ActualWidth`, `ActualHeight` on initialization. Fortuately, the second option was something else that was already on my backlog of bugs. #4618 - `wt` command-line can't consistently parse more than one arg Presently, the Terminal just arbitrarily dispatches a bunch of handlers to try and handle all the commands provided on the commandline. That's lead to a bunch of reports that not all the commands will always get executed, nor will they all get executed in the same order. This PR also changes the `TerminalPage` to be able to dispatch all the commands sequentially, all at once in the startup. No longer will there be a hot second where the commands seem to execute themselves in from of the user - they'll all happen behind the scenes on startup. This involved a couple other changes areound the `TerminalPage` * I had to make sure that panes could be opened at a 0x0 size. Now they use a star sizing based off the percentage of the parent they're supposed to consume, so that when the parent _does_ get laid out, they'll take the appropriate size of that parent. * I had to do some math ahead of time to try and calculate what a `SplitState::Automatic` would be evaluated as, despite the fact that we don't actually know how big the pane will be. * I had to ensure that `focus-tab` commands appropriately mark a single tab as focused while we're in startup, without roundtripping to the Dispatcher thread and back ## References #4429 - the original PR for #2455 #5047 - a follow-up task from discussion in #4429 #4953 - a PR for making panes use star sizing, which was immensly helpful for this PR. ## Detailed Description of the Pull Request / Additional comments `CascadiaSettings::BuildSettings` can throw if the GUID doesn't exist. This wraps those calls up with a try/catch. It also adds a couple tests - a few `SettingsTests` for try/catching this state. It also adds a XAML-y test in `TabTests` that creates a `TerminalPage` and then performs som UI-like actions on it. This test required a minor change to how we generate the new tab dropdown - in the tests, `Application::Current()` is _not_ a `TerminalApp::App`, so it doesn't have a `Logic()` to query. So wrap that in a try/catch as well. While working on these tests, I found that we'd crash pretty agressively for mysterious reasons if the TestHostApp became focused while the test was running. This was due to a call in `TSFInputControl::NotifyFocusEnter` that would callback to `TSFInputControl::_layoutRequested`, which would crash on setting the `MaxSize` of the canvas to a negative value. This PR includes a hotfix for that bug as well. ## Validation Steps Performed * Manual testing with a _lot_ of commands in a commandline * run the tests * Team tested in selfhost Closes #2455 Closes #4618
2020-03-26 01:03:32 +01:00
// Manually enumerate the panes in each tab; this will let us recycle TerminalSettings
// objects but only have to iterate one time.
terminalTab->GetRootPane()->WalkTree([&](auto&& pane) {
if (const auto profile{ pane->GetProfile() })
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
{
const auto found{ profileGuidSettingsMap.find(profile.Guid()) };
// GH#2455: If there are any panes with controls that had been
// initialized with a Profile that no longer exists in our list of
// profiles, we'll leave it unmodified. The profile doesn't exist
// anymore, so we can't possibly update its settings.
if (found != profileGuidSettingsMap.cend())
{
auto& pair{ found->second };
if (!pair.second)
{
pair.second = TerminalSettings::CreateWithProfile(_settings, pair.first, *_bindings);
}
pane->UpdateSettings(pair.second, pair.first);
}
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
}
return false;
});
// Update the icon of the tab for the currently focused profile in that tab.
// Only do this for TerminalTabs. Other types of tabs won't have multiple panes
// and profiles so the Title and Icon will be set once and only once on init.
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
_UpdateTabIcon(*terminalTab);
// Force the TerminalTab to re-grab its currently active control's title.
terminalTab->UpdateTitle();
}
else if (auto settingsTab = tab.try_as<TerminalApp::SettingsTab>())
{
settingsTab.UpdateSettings(_settings);
}
auto tabImpl{ winrt::get_self<TabBase>(tab) };
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
tabImpl->SetActionMap(_settings.ActionMap());
}
Converts Dispatcher().RunAsync to WinRT Coroutines (#4051) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR turns all* instances of `Dispatcher().RunAsync` to WinRT coroutines 👌. This was good coding fodder to fill my plane ride ✈️. Enjoy your holidays everyone! *With the exception of three functions whose signatures cannot be changed due to inheritance and function overriding in `TermControlAutomationPeer` [`L44`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L44), [`L58`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L58), [`L72`](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp#L72). <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3919 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be 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: #3919 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments My thought pattern here was to minimally disturb the existing code where possible. So where I could, I converted existing functions into coroutine using functions (like in the [core example](https://github.com/microsoft/terminal/issues/3919#issue-536598706)). For ~the most part~ all instances, I used the format where [`this` is accessed safely within a locked scope](https://github.com/microsoft/terminal/issues/3919#issuecomment-564730620). Some function signatures were changed to take objects by value instead of reference, so the coroutines don't crash when the objects are accessed past their original lifetime. The [copy](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1132) and [paste](https://github.com/microsoft/terminal/blob/master/src/cascadia/TerminalApp/TerminalPage.cpp#L1170) event handler entry points were originally set to a high priority; however, the WinRT coroutines don't appear to support a priority scheme so this priority setting was not preserved in the translation. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Compiles and runs, and for every event with a clear trigger repro, I triggered it to ensure crashes weren't introduced.
2020-01-10 04:29:49 +01:00
// repopulate the new tab button's flyout with entries for each
// profile, which might have changed
_UpdateTabWidthMode();
_CreateNewTabFlyout();
// Reload the current value of alwaysOnTop from the settings file. This
// will let the user hot-reload this setting, but any runtime changes to
// the alwaysOnTop setting will be lost.
_isAlwaysOnTop = _settings.GlobalSettings().AlwaysOnTop();
_AlwaysOnTopChangedHandlers(*this, nullptr);
// Settings AllowDependentAnimations will affect whether animations are
// enabled application-wide, so we don't need to check it each time we
// want to create an animation.
WUX::Media::Animation::Timeline::AllowDependentAnimations(!_settings.GlobalSettings().DisableAnimations());
_tabRow.ShowElevationShield(IsElevated() && _settings.GlobalSettings().ShowAdminShield());
}
// This is a helper to aid in sorting commands by their `Name`s, alphabetically.
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
static bool _compareSchemeNames(const ColorScheme& lhs, const ColorScheme& rhs)
{
std::wstring leftName{ lhs.Name() };
std::wstring rightName{ rhs.Name() };
return leftName.compare(rightName) < 0;
}
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
// Method Description:
// - Takes a mapping of names->commands and expands them
// Arguments:
// - <none>
// Return Value:
// - <none>
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
IMap<winrt::hstring, Command> TerminalPage::_ExpandCommands(IMapView<winrt::hstring, Command> commandsToExpand,
IVectorView<Profile> profiles,
IMapView<winrt::hstring, ColorScheme> schemes)
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
{
IVector<SettingsLoadWarnings> warnings{ winrt::single_threaded_vector<SettingsLoadWarnings>() };
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
std::vector<ColorScheme> sortedSchemes;
sortedSchemes.reserve(schemes.Size());
for (const auto& nameAndScheme : schemes)
{
sortedSchemes.push_back(nameAndScheme.Value());
}
std::sort(sortedSchemes.begin(),
sortedSchemes.end(),
_compareSchemeNames);
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
IMap<winrt::hstring, Command> copyOfCommands = winrt::single_threaded_map<winrt::hstring, Command>();
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
for (const auto& nameAndCommand : commandsToExpand)
{
copyOfCommands.Insert(nameAndCommand.Key(), nameAndCommand.Value());
}
Command::ExpandCommands(copyOfCommands,
profiles,
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
{ sortedSchemes },
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
warnings);
return copyOfCommands;
}
// Method Description:
// - Repopulates the list of commands in the command palette with the
// current commands in the settings. Also updates the keybinding labels to
// reflect any matching keybindings.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_UpdateCommandsForPalette()
{
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
IMap<winrt::hstring, Command> copyOfCommands = _ExpandCommands(_settings.GlobalSettings().ActionMap().NameMap(),
_settings.ActiveProfiles().GetView(),
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
_settings.GlobalSettings().ColorSchemes());
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
_recursiveUpdateCommandKeybindingLabels(_settings, copyOfCommands.GetView());
// Update the command palette when settings reload
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
auto commandsCollection = winrt::single_threaded_vector<Command>();
Add support for iterable, nested commands (#6856) ## Summary of the Pull Request This PR adds support for both _nested_ and _iterable_ commands in the Command palette. ![nested-commands-000](https://user-images.githubusercontent.com/18356694/87072916-2d991c00-c1e2-11ea-8917-a70e8b8b9803.gif) * **Nested commands**: These are commands that include additional sub-commands. When the user selects on of these, the palette will update to only show the nested commands. * **Iterable commands**: These are commands what allow the user to define only a single command, which is repeated once for every profile. (in the future, also repeated for color schemes, themes, etc.) The above gif uses the following json: ```json { "name": "Split Pane...", "commands": [ { "iterateOn": "profiles", "name": "Split with ${profile.name}...", "commands": [ { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "automatic" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "vertical" } }, { "command": { "action": "splitPane", "profile": "${profile.name}", "split": "horizontal" } } ] } ] }, ``` ## References ## PR Checklist * [x] Closes #3994 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - Sure does, but we'll finish polishing this first. ## Detailed Description of the Pull Request / Additional comments We've now gotta keep the original json for a command around, so that once we know what all the profiles will be, we can expand the commands that need it. We've also got to parse commands recursively, because they might have any number of child commands. These together made the command parsing a _lot_ more complicated, but it feels good so far. ## Validation Steps Performed * wrote a bunch of tests * Played with it a bunch
2020-08-13 23:22:46 +02:00
for (const auto& nameAndCommand : copyOfCommands)
{
commandsCollection.Append(nameAndCommand.Value());
}
CommandPalette().SetCommands(commandsCollection);
}
// Method Description:
// - Sets the initial actions to process on startup. We'll make a copy of
// this list, and process these actions when we're loaded.
// - This function will have no effective result after Create() is called.
// Arguments:
// - actions: a list of Actions to process on startup.
// Return Value:
// - <none>
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
void TerminalPage::SetStartupActions(std::vector<ActionAndArgs>& actions)
{
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
// The fastest way to copy all the actions out of the std::vector and
// put them into a winrt::IVector is by making a copy, then moving the
// copy into the winrt vector ctor.
auto listCopy = actions;
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
_startupActions = winrt::single_threaded_vector<ActionAndArgs>(std::move(listCopy));
}
// Routine Description:
// - Notifies this Terminal Page that it should start the incoming connection
// listener for command-line tools attempting to join this Terminal
// through the default application channel.
// Arguments:
// - isEmbedding - True if COM started us to be a server. False if we're doing it of our own accord.
// Return Value:
// - <none>
void TerminalPage::SetInboundListener(bool isEmbedding)
{
_shouldStartInboundListener = true;
_isEmbeddingInboundListener = isEmbedding;
// If the page has already passed the NotInitialized state,
// then it is ready-enough for us to just start this immediately.
if (_startupState != StartupState::NotInitialized)
{
_StartInboundListener();
}
}
winrt::TerminalApp::IDialogPresenter TerminalPage::DialogPresenter() const
{
return _dialogPresenter.get();
}
void TerminalPage::DialogPresenter(winrt::TerminalApp::IDialogPresenter dialogPresenter)
{
_dialogPresenter = dialogPresenter;
}
// Method Description:
Combine progress states in the tab, taskbar (#10755) ## Summary of the Pull Request ![background-progress-000](https://user-images.githubusercontent.com/18356694/126653006-3ad2fdae-67ae-4cdb-aa46-25d09217e365.gif) This PR causes the Terminal to combine taskbar states at the tab and window level, according to the [MSDN docs for `SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group). This allows the Terminal's taskbar icon to continue showing progress information, even if you're in a pane/tab that _doesn't_ have progress state. This is helpful for cases where the user may be running a build in one tab, and working on something else in another. ## References * [`SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group) * Progress mega: #6700 ## PR Checklist * [x] Closes #10090 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments This also fixes a related bug where transitioning from the "error" or "warning" state directly to the "indeterminate" state would cause the taskbar icon to get stuck in a bad state. ## Validation Steps Performed <details> <summary><code>progress.cmd</code></summary> ```cmd @echo off setlocal enabledelayedexpansion set _type=3 if (%1) == () ( set _type=3 ) else ( set _type=%1 ) if (%_type%) == (0) ( <NUL set /p =]9;4 echo Cleared progress ) if (%_type%) == (1) ( <NUL set /p =]9;4;1;25 echo Started progress (normal, 25^) ) if (%_type%) == (2) ( <NUL set /p =]9;4;2;50 echo Started progress (error, 50^) ) if (%_type%) == (3) ( @rem start indeterminate progress in the taskbar @rem this `<NUL set /p =` magic will output the text _without a newline_ <NUL set /p =]9;4;3 echo Started progress (indeterminate, {omitted}) ) if (%_type%) == (4) ( <NUL set /p =]9;4;4;75 echo Started progress (warning, 75^) ) ``` </details>
2021-08-10 13:16:17 +02:00
// - Get the combined taskbar state for the page. This is the combination of
// all the states of all the tabs, which are themselves a combination of
// all their panes. Taskbar states are given a priority based on the rules
// in:
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate
// under "How the Taskbar Button Chooses the Progress Indicator for a Group"
// Arguments:
// - <none>
// Return Value:
Combine progress states in the tab, taskbar (#10755) ## Summary of the Pull Request ![background-progress-000](https://user-images.githubusercontent.com/18356694/126653006-3ad2fdae-67ae-4cdb-aa46-25d09217e365.gif) This PR causes the Terminal to combine taskbar states at the tab and window level, according to the [MSDN docs for `SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group). This allows the Terminal's taskbar icon to continue showing progress information, even if you're in a pane/tab that _doesn't_ have progress state. This is helpful for cases where the user may be running a build in one tab, and working on something else in another. ## References * [`SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group) * Progress mega: #6700 ## PR Checklist * [x] Closes #10090 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments This also fixes a related bug where transitioning from the "error" or "warning" state directly to the "indeterminate" state would cause the taskbar icon to get stuck in a bad state. ## Validation Steps Performed <details> <summary><code>progress.cmd</code></summary> ```cmd @echo off setlocal enabledelayedexpansion set _type=3 if (%1) == () ( set _type=3 ) else ( set _type=%1 ) if (%_type%) == (0) ( <NUL set /p =]9;4 echo Cleared progress ) if (%_type%) == (1) ( <NUL set /p =]9;4;1;25 echo Started progress (normal, 25^) ) if (%_type%) == (2) ( <NUL set /p =]9;4;2;50 echo Started progress (error, 50^) ) if (%_type%) == (3) ( @rem start indeterminate progress in the taskbar @rem this `<NUL set /p =` magic will output the text _without a newline_ <NUL set /p =]9;4;3 echo Started progress (indeterminate, {omitted}) ) if (%_type%) == (4) ( <NUL set /p =]9;4;4;75 echo Started progress (warning, 75^) ) ``` </details>
2021-08-10 13:16:17 +02:00
// - A TaskbarState object representing the combined taskbar state and
// progress percentage of all our tabs.
winrt::TerminalApp::TaskbarState TerminalPage::TaskbarState() const
{
Combine progress states in the tab, taskbar (#10755) ## Summary of the Pull Request ![background-progress-000](https://user-images.githubusercontent.com/18356694/126653006-3ad2fdae-67ae-4cdb-aa46-25d09217e365.gif) This PR causes the Terminal to combine taskbar states at the tab and window level, according to the [MSDN docs for `SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group). This allows the Terminal's taskbar icon to continue showing progress information, even if you're in a pane/tab that _doesn't_ have progress state. This is helpful for cases where the user may be running a build in one tab, and working on something else in another. ## References * [`SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group) * Progress mega: #6700 ## PR Checklist * [x] Closes #10090 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments This also fixes a related bug where transitioning from the "error" or "warning" state directly to the "indeterminate" state would cause the taskbar icon to get stuck in a bad state. ## Validation Steps Performed <details> <summary><code>progress.cmd</code></summary> ```cmd @echo off setlocal enabledelayedexpansion set _type=3 if (%1) == () ( set _type=3 ) else ( set _type=%1 ) if (%_type%) == (0) ( <NUL set /p =]9;4 echo Cleared progress ) if (%_type%) == (1) ( <NUL set /p =]9;4;1;25 echo Started progress (normal, 25^) ) if (%_type%) == (2) ( <NUL set /p =]9;4;2;50 echo Started progress (error, 50^) ) if (%_type%) == (3) ( @rem start indeterminate progress in the taskbar @rem this `<NUL set /p =` magic will output the text _without a newline_ <NUL set /p =]9;4;3 echo Started progress (indeterminate, {omitted}) ) if (%_type%) == (4) ( <NUL set /p =]9;4;4;75 echo Started progress (warning, 75^) ) ``` </details>
2021-08-10 13:16:17 +02:00
auto state{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>() };
Combine progress states in the tab, taskbar (#10755) ## Summary of the Pull Request ![background-progress-000](https://user-images.githubusercontent.com/18356694/126653006-3ad2fdae-67ae-4cdb-aa46-25d09217e365.gif) This PR causes the Terminal to combine taskbar states at the tab and window level, according to the [MSDN docs for `SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group). This allows the Terminal's taskbar icon to continue showing progress information, even if you're in a pane/tab that _doesn't_ have progress state. This is helpful for cases where the user may be running a build in one tab, and working on something else in another. ## References * [`SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group) * Progress mega: #6700 ## PR Checklist * [x] Closes #10090 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments This also fixes a related bug where transitioning from the "error" or "warning" state directly to the "indeterminate" state would cause the taskbar icon to get stuck in a bad state. ## Validation Steps Performed <details> <summary><code>progress.cmd</code></summary> ```cmd @echo off setlocal enabledelayedexpansion set _type=3 if (%1) == () ( set _type=3 ) else ( set _type=%1 ) if (%_type%) == (0) ( <NUL set /p =]9;4 echo Cleared progress ) if (%_type%) == (1) ( <NUL set /p =]9;4;1;25 echo Started progress (normal, 25^) ) if (%_type%) == (2) ( <NUL set /p =]9;4;2;50 echo Started progress (error, 50^) ) if (%_type%) == (3) ( @rem start indeterminate progress in the taskbar @rem this `<NUL set /p =` magic will output the text _without a newline_ <NUL set /p =]9;4;3 echo Started progress (indeterminate, {omitted}) ) if (%_type%) == (4) ( <NUL set /p =]9;4;4;75 echo Started progress (warning, 75^) ) ``` </details>
2021-08-10 13:16:17 +02:00
for (const auto& tab : _tabs)
{
Combine progress states in the tab, taskbar (#10755) ## Summary of the Pull Request ![background-progress-000](https://user-images.githubusercontent.com/18356694/126653006-3ad2fdae-67ae-4cdb-aa46-25d09217e365.gif) This PR causes the Terminal to combine taskbar states at the tab and window level, according to the [MSDN docs for `SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group). This allows the Terminal's taskbar icon to continue showing progress information, even if you're in a pane/tab that _doesn't_ have progress state. This is helpful for cases where the user may be running a build in one tab, and working on something else in another. ## References * [`SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group) * Progress mega: #6700 ## PR Checklist * [x] Closes #10090 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments This also fixes a related bug where transitioning from the "error" or "warning" state directly to the "indeterminate" state would cause the taskbar icon to get stuck in a bad state. ## Validation Steps Performed <details> <summary><code>progress.cmd</code></summary> ```cmd @echo off setlocal enabledelayedexpansion set _type=3 if (%1) == () ( set _type=3 ) else ( set _type=%1 ) if (%_type%) == (0) ( <NUL set /p =]9;4 echo Cleared progress ) if (%_type%) == (1) ( <NUL set /p =]9;4;1;25 echo Started progress (normal, 25^) ) if (%_type%) == (2) ( <NUL set /p =]9;4;2;50 echo Started progress (error, 50^) ) if (%_type%) == (3) ( @rem start indeterminate progress in the taskbar @rem this `<NUL set /p =` magic will output the text _without a newline_ <NUL set /p =]9;4;3 echo Started progress (indeterminate, {omitted}) ) if (%_type%) == (4) ( <NUL set /p =]9;4;4;75 echo Started progress (warning, 75^) ) ``` </details>
2021-08-10 13:16:17 +02:00
if (auto tabImpl{ _GetTerminalTabImpl(tab) })
{
auto tabState{ tabImpl->GetCombinedTaskbarState() };
// lowest priority wins
if (tabState.Priority() < state.Priority())
{
state = tabState;
}
}
}
Combine progress states in the tab, taskbar (#10755) ## Summary of the Pull Request ![background-progress-000](https://user-images.githubusercontent.com/18356694/126653006-3ad2fdae-67ae-4cdb-aa46-25d09217e365.gif) This PR causes the Terminal to combine taskbar states at the tab and window level, according to the [MSDN docs for `SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group). This allows the Terminal's taskbar icon to continue showing progress information, even if you're in a pane/tab that _doesn't_ have progress state. This is helpful for cases where the user may be running a build in one tab, and working on something else in another. ## References * [`SetProgressState`](https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group) * Progress mega: #6700 ## PR Checklist * [x] Closes #10090 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments This also fixes a related bug where transitioning from the "error" or "warning" state directly to the "indeterminate" state would cause the taskbar icon to get stuck in a bad state. ## Validation Steps Performed <details> <summary><code>progress.cmd</code></summary> ```cmd @echo off setlocal enabledelayedexpansion set _type=3 if (%1) == () ( set _type=3 ) else ( set _type=%1 ) if (%_type%) == (0) ( <NUL set /p =]9;4 echo Cleared progress ) if (%_type%) == (1) ( <NUL set /p =]9;4;1;25 echo Started progress (normal, 25^) ) if (%_type%) == (2) ( <NUL set /p =]9;4;2;50 echo Started progress (error, 50^) ) if (%_type%) == (3) ( @rem start indeterminate progress in the taskbar @rem this `<NUL set /p =` magic will output the text _without a newline_ <NUL set /p =]9;4;3 echo Started progress (indeterminate, {omitted}) ) if (%_type%) == (4) ( <NUL set /p =]9;4;4;75 echo Started progress (warning, 75^) ) ``` </details>
2021-08-10 13:16:17 +02:00
return state;
}
// Method Description:
// - This is the method that App will call when the titlebar
// has been clicked. It dismisses any open flyouts.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::TitlebarClicked()
{
if (_newTabButton && _newTabButton.Flyout())
{
_newTabButton.Flyout().Hide();
}
minor refactor: Move Tab management into its own file (#9629) I think we can all agree that `TerminalPage.cpp` is an unruly beast of a file. It's got everything. It does everything. It can sometimes be a bit hard to work with, because of simply how big it is. This PR tries to alleviate this by making `TerminalPage.cpp` just a little smaller. It does so by moving pretty much everything related to tab management into its own file, `TabManagement.cpp`. These methods that have moved are all the same as they were before, and they're still members of `TerminalPage`. But now they're all in one place. I tried to move all the references to `_tabs` in `TerminalPage.cpp`, but there's still a few that I left behind. Mostly because I felt that moving those would be too gnarly a code change for an otherwise simple cut&paste PR. There are a few new methods I introduced: * `_TabDragStarted` and `_TabDragCompleted`: These were lambdas before, promoted to full methods. * `_DismissTabContextMenus`: Remove all the right-click context menus from the tabs * `_FocusCurrentTab`: This one's a bit trickier, we were actually doing this in a few different places, so I tried consolidating. * `_HasMultipleTabs`: This doesn't need explaining. * `_RemoveAllTabs`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` * `_ResizeTabContent`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` In the future, some enterprising young soul could try promoting that file to its own class, and hiding `_tabs` (and `_mruTabs`) inside it. Probably would need to take a reference to TerminalPage's `_tabView` and `_newTabButton`. I'm not doing that right now, because I already hate the idea of the ... > 920 additions and 847 deletions. ... I'm making you look at already. ## Other thoughts Some of the calls might be a little arbitrary - `_OpenNewTab` and `_CreateNewTabFromSettings` probably should stay in `TerminalPage`? Or at least elements of those might need to get split up better. Similarly `TerminalPage::_OpenSettingsUI` stayed in `TerminalPage.cpp`, but it does a lot of the same work as `_CreateNewTabFromSettings`. I'm not saying this is the definitive places for these methods - it's code we're working with, not stone ☺️
2021-03-29 21:53:39 +02:00
_DismissTabContextMenus();
}
Search - add search box control and implement search experience (#3590) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> This is the PR for feature Search: #605 This PR includes the newly introduced SearchBoxControl in TermControl dir, which is the search bar for the search experience. And the codes that enable Search in Windows Terminal. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> The PR that migrates the Conhost search module: https://github.com/microsoft/terminal/pull/3279 Spec (still actively updating): https://github.com/microsoft/terminal/pull/3299 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #605 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be updated * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> These functionalities are included in the search experience. 1. Search in Terminal text buffer. 2. Automatic wrap-around. 3. Search up or down switch by clicking different buttons. 4. Search case sensitively/insensitively by clicking a button. S. Move the search box to the top/bottom by clicking a button. 6. Close by clicking 'X'. 7. Open search by ctrl + F. When the searchbox is open, the user could still interact with the terminal by clicking the terminal input area. While I already have the search functionalities, currently there are still some known to-do works and I will keep updating my PR: 1. Optimize the search box UI, this includes: 1) Theme adaptation. The search box background and font color should change according to the theme, 2) Add background. Currently the elements in search box are all transparent. However, we need a background. 3) Move button should be highlighted once clicked. 2. Accessibility: search process should be able to performed without mouse. Once the search box is focused, the user should be able to navigate between all interactive elements on the searchbox using keyboard. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> To test: 1. checkout this branch. 2. Build the project. 3. Start Windows Terminal and press Ctrl+F 4. The search box should appear on the top right corner.
2019-12-17 16:52:37 +01:00
// Method Description:
// - Called when the user tries to do a search using keybindings.
// This will tell the current focused terminal control to create
// a search box and enable find process.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_Find()
{
Hook up the keybindings to the SUI, redux (#10121) ## Summary of the Pull Request This is a redux of #8882. From the original: > This is really similar to what we're doing with the `CommandPalette`. We're adding a ~~Preview~~`KeyDown` handler to the SUI `MainPage`, that connects to `TerminalPage::_HandleKey`. That allows the SUI a chance to search the keymap to dispatch actions for keybindings, similar to how the command palette does it. > > This also means it's now possible for the SUI to invoke _all_ the actions available to the Terminal. This includes the ones like `IncreaseFontSize`, which require a _Terminal_ to actually do something. So we have to make sure all the calls to `_GetActiveControl` actually check that the result is non-null before using it. > > A bunch of the actions do nothing now from a SUI tab, others behave _weird_. Like "Rename tab" / "Open Tab Renamer" do nothing. "Duplicate Tab" again does nothing - we try making a new settings tab, which just focuses the settings tab again. "Copy text" definitely does nothing, same with paste. I don't know why I thought this wouldn't work. I thought we'd have to do this in `PreviewKeyDown` or something, which led to [weirdness](https://github.com/microsoft/terminal/pull/8882#issuecomment-767088554). Turns out, we don't need it to be in `PreviewKeyDown`. It can just be in the SUI's `KeyDown`. ## References * Original: #8882 * Workaround was in #8885 ## PR Checklist * [x] Closes #8767 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments The special case handler from #8885 is no longer needed ## Validation Steps Performed * Switching tabs with Ctrl+Tab works * Command palette works * fullscreen, focus mode works * close window works * copy paste on Ctrl+C/V works, even when bound * Select all text in textboxes works * tab navigation through UI elements works
2021-05-24 21:18:38 +02:00
if (const auto& control{ _GetActiveControl() })
{
control.CreateSearchBoxControl();
}
Search - add search box control and implement search experience (#3590) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> This is the PR for feature Search: #605 This PR includes the newly introduced SearchBoxControl in TermControl dir, which is the search bar for the search experience. And the codes that enable Search in Windows Terminal. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> The PR that migrates the Conhost search module: https://github.com/microsoft/terminal/pull/3279 Spec (still actively updating): https://github.com/microsoft/terminal/pull/3299 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #605 * [ ] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Requires documentation to be updated * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> These functionalities are included in the search experience. 1. Search in Terminal text buffer. 2. Automatic wrap-around. 3. Search up or down switch by clicking different buttons. 4. Search case sensitively/insensitively by clicking a button. S. Move the search box to the top/bottom by clicking a button. 6. Close by clicking 'X'. 7. Open search by ctrl + F. When the searchbox is open, the user could still interact with the terminal by clicking the terminal input area. While I already have the search functionalities, currently there are still some known to-do works and I will keep updating my PR: 1. Optimize the search box UI, this includes: 1) Theme adaptation. The search box background and font color should change according to the theme, 2) Add background. Currently the elements in search box are all transparent. However, we need a background. 3) Move button should be highlighted once clicked. 2. Accessibility: search process should be able to performed without mouse. Once the search box is focused, the user should be able to navigate between all interactive elements on the searchbox using keyboard. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> To test: 1. checkout this branch. 2. Build the project. 3. Start Windows Terminal and press Ctrl+F 4. The search box should appear on the top right corner.
2019-12-17 16:52:37 +01:00
}
// Method Description:
// - Toggles borderless mode. Hides the tab row, and raises our
// FocusModeChanged event.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::ToggleFocusMode()
{
Make the window name `_quake` special (#9785) ## Summary of the Pull Request This PR adds some special behavior to the window named "\_quake". * When creating the quake window, it ignores "initialRows" and "initialCols" and opens on the top half of the monitor. - It uses `initialPosition` to determine which monitor this is * It cannot be moved * It can only be vertically resized on the bottom border. * It's always in focus mode. - We should probably have an issue tracking "Allow showing tabs in focus mode"? Maybe? - This one element is maybe the one I'm least attached to When renaming a window to "\_quake", it adopts all those behaviors as well. It does not exit focus mode when leaving QM, nor does it resize back. That seemed unnecessary. ## References * As spec'ed in #9274 * See also #8888 ## PR Checklist * [x] In the pursuit of #653 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated, but I'm not gonna do any of that till quake mode is totally done. ## Detailed Description of the Pull Request / Additional comments Note that this doesn't do things like: * dropdown * global hotkey summon * summon to the current monitor * summon to the current desktop I'm doing #653 _very_ piecemeal, to try and make the PRs less egregious. ## Validation Steps Performed * validated that center on launch still works * validated that QM works on different monitors based on `initialPosition` * validated entering/exiting QM behaves as expected ## TODO! * [ ] When snapping the quake window between desktops with <kbd>win+shift+arrow</kbd>, the window doesn't horizontally re-size to the new monitor dimensions. It should.
2021-04-26 21:36:23 +02:00
_SetFocusMode(!_isInFocusMode);
}
void TerminalPage::_SetFocusMode(const bool inFocusMode)
{
const bool newInFocusMode = inFocusMode;
Make the window name `_quake` special (#9785) ## Summary of the Pull Request This PR adds some special behavior to the window named "\_quake". * When creating the quake window, it ignores "initialRows" and "initialCols" and opens on the top half of the monitor. - It uses `initialPosition` to determine which monitor this is * It cannot be moved * It can only be vertically resized on the bottom border. * It's always in focus mode. - We should probably have an issue tracking "Allow showing tabs in focus mode"? Maybe? - This one element is maybe the one I'm least attached to When renaming a window to "\_quake", it adopts all those behaviors as well. It does not exit focus mode when leaving QM, nor does it resize back. That seemed unnecessary. ## References * As spec'ed in #9274 * See also #8888 ## PR Checklist * [x] In the pursuit of #653 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated, but I'm not gonna do any of that till quake mode is totally done. ## Detailed Description of the Pull Request / Additional comments Note that this doesn't do things like: * dropdown * global hotkey summon * summon to the current monitor * summon to the current desktop I'm doing #653 _very_ piecemeal, to try and make the PRs less egregious. ## Validation Steps Performed * validated that center on launch still works * validated that QM works on different monitors based on `initialPosition` * validated entering/exiting QM behaves as expected ## TODO! * [ ] When snapping the quake window between desktops with <kbd>win+shift+arrow</kbd>, the window doesn't horizontally re-size to the new monitor dimensions. It should.
2021-04-26 21:36:23 +02:00
if (newInFocusMode != FocusMode())
{
_isInFocusMode = newInFocusMode;
_UpdateTabView();
_FocusModeChangedHandlers(*this, nullptr);
}
}
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
// Method Description:
// - Toggles fullscreen mode. Hides the tab row, and raises our
// FullscreenChanged event.
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::ToggleFullscreen()
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
{
_isFullscreen = !_isFullscreen;
_UpdateTabView();
_FullscreenChangedHandlers(*this, nullptr);
}
// Method Description:
// - Toggles always on top mode. Raises our AlwaysOnTopChanged event.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::ToggleAlwaysOnTop()
{
_isAlwaysOnTop = !_isAlwaysOnTop;
_AlwaysOnTopChangedHandlers(*this, nullptr);
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
}
// Method Description:
// - Sets the tab split button color when a new tab color is selected
// Arguments:
// - color: The color of the newly selected tab, used to properly calculate
// the foreground color of the split button (to match the font
// color of the tab)
// - accentColor: the actual color we are going to use to paint the tab row and
// split button, so that there is some contrast between the tab
// and the non-client are behind it
// Return Value:
// - <none>
void TerminalPage::_SetNewTabButtonColor(const Windows::UI::Color& color, const Windows::UI::Color& accentColor)
{
// TODO GH#3327: Look at what to do with the tab button when we have XAML theming
bool IsBrightColor = ColorHelper::IsBrightColor(color);
bool isLightAccentColor = ColorHelper::IsBrightColor(accentColor);
winrt::Windows::UI::Color pressedColor{};
winrt::Windows::UI::Color hoverColor{};
winrt::Windows::UI::Color foregroundColor{};
const float hoverColorAdjustment = 5.f;
const float pressedColorAdjustment = 7.f;
if (IsBrightColor)
{
foregroundColor = winrt::Windows::UI::Colors::Black();
}
else
{
foregroundColor = winrt::Windows::UI::Colors::White();
}
if (isLightAccentColor)
{
hoverColor = ColorHelper::Darken(accentColor, hoverColorAdjustment);
pressedColor = ColorHelper::Darken(accentColor, pressedColorAdjustment);
}
else
{
hoverColor = ColorHelper::Lighten(accentColor, hoverColorAdjustment);
pressedColor = ColorHelper::Lighten(accentColor, pressedColorAdjustment);
}
Media::SolidColorBrush backgroundBrush{ accentColor };
Media::SolidColorBrush backgroundHoverBrush{ hoverColor };
Media::SolidColorBrush backgroundPressedBrush{ pressedColor };
Media::SolidColorBrush foregroundBrush{ foregroundColor };
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonBackground"), backgroundBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonBackgroundPointerOver"), backgroundHoverBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonBackgroundPressed"), backgroundPressedBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonForeground"), foregroundBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonForegroundPointerOver"), foregroundBrush);
_newTabButton.Resources().Insert(winrt::box_value(L"SplitButtonForegroundPressed"), foregroundBrush);
_newTabButton.Background(backgroundBrush);
_newTabButton.Foreground(foregroundBrush);
}
// Method Description:
// - Clears the tab split button color to a system color
// (or white if none is found) when the tab's color is cleared
// - Clears the tab row color to a system color
// (or white if none is found) when the tab's color is cleared
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_ClearNewTabButtonColor()
{
// TODO GH#3327: Look at what to do with the tab button when we have XAML theming
winrt::hstring keys[] = {
L"SplitButtonBackground",
L"SplitButtonBackgroundPointerOver",
L"SplitButtonBackgroundPressed",
L"SplitButtonForeground",
L"SplitButtonForegroundPointerOver",
L"SplitButtonForegroundPressed"
};
// simply clear any of the colors in the split button's dict
for (auto keyString : keys)
{
auto key = winrt::box_value(keyString);
if (_newTabButton.Resources().HasKey(key))
{
_newTabButton.Resources().Remove(key);
}
}
const auto res = Application::Current().Resources();
const auto defaultBackgroundKey = winrt::box_value(L"TabViewItemHeaderBackground");
const auto defaultForegroundKey = winrt::box_value(L"SystemControlForegroundBaseHighBrush");
winrt::Windows::UI::Xaml::Media::SolidColorBrush backgroundBrush;
winrt::Windows::UI::Xaml::Media::SolidColorBrush foregroundBrush;
// TODO: Related to GH#3917 - I think if the system is set to "Dark"
// theme, but the app is set to light theme, then this lookup still
// returns to us the dark theme brushes. There's gotta be a way to get
// the right brushes...
// See also GH#5741
if (res.HasKey(defaultBackgroundKey))
{
winrt::Windows::Foundation::IInspectable obj = res.Lookup(defaultBackgroundKey);
backgroundBrush = obj.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
}
else
{
backgroundBrush = winrt::Windows::UI::Xaml::Media::SolidColorBrush{ winrt::Windows::UI::Colors::Black() };
}
if (res.HasKey(defaultForegroundKey))
{
winrt::Windows::Foundation::IInspectable obj = res.Lookup(defaultForegroundKey);
foregroundBrush = obj.try_as<winrt::Windows::UI::Xaml::Media::SolidColorBrush>();
}
else
{
foregroundBrush = winrt::Windows::UI::Xaml::Media::SolidColorBrush{ winrt::Windows::UI::Colors::White() };
}
_newTabButton.Background(backgroundBrush);
_newTabButton.Foreground(foregroundBrush);
}
// Method Description:
// - Sets the tab split button color when a new tab color is selected
// - This method could also set the color of the title bar and tab row
// in the future
// Arguments:
// - selectedTabColor: The color of the newly selected tab
// Return Value:
// - <none>
void TerminalPage::_SetNonClientAreaColors(const Windows::UI::Color& /*selectedTabColor*/)
{
// TODO GH#3327: Look at what to do with the NC area when we have XAML theming
}
// Method Description:
// - Clears the tab split button color when the tab's color is cleared
// - This method could also clear the color of the title bar and tab row
// in the future
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_ClearNonClientAreaColors()
{
// TODO GH#3327: Look at what to do with the NC area when we have XAML theming
}
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
// Function Description:
// - This is a helper method to get the commandline out of a
// ExecuteCommandline action, break it into subcommands, and attempt to
// parse it into actions. This is used by _HandleExecuteCommandline for
// processing commandlines in the current WT window.
// Arguments:
// - args: the ExecuteCommandlineArgs to synthesize a list of startup actions for.
// Return Value:
// - an empty list if we failed to parse, otherwise a list of actions to execute.
Introduce TerminalSettingsModel project (#7667) Introduces a new TerminalSettingsModel (TSM) project. This project is responsible for (de)serializing and exposing Windows Terminal's settings as WinRT objects. ## References #885: TSM epic #1564: Settings UI is dependent on this for data binding and settings access #6904: TSM Spec In the process of ripping out TSM from TerminalApp, a few other changes were made to make this possible: 1. AppLogic's `ApplicationDisplayName` and `ApplicationVersion` was moved to `CascadiaSettings` - These are defined as static functions. They also no longer check if `AppLogic::Current()` is nullptr. 2. `enum LaunchMode` was moved from TerminalApp to TSM 3. `AzureConnectionType` and `TelnetConnectionType` were moved from the profile generators to their respective TerminalConnections 4. CascadiaSettings' `SettingsPath` and `DefaultSettingsPath` are exposed as `hstring` instead of `std::filesystem::path` 5. `Command::ExpandCommands()` was exposed via the IDL - This required some of the warnings to be saved to an `IVector` instead of `std::vector`, among some other small changes. 6. The localization resources had to be split into two halves. - Resource file linked in init.cpp. Verified at runtime thanks to the StaticResourceLoader. 7. Added constructors to some `ActionArgs` 8. Utils.h/cpp were moved to `cascadia/inc`. `JsonKey()` was moved to `JsonUtils`. Both TermApp and TSM need access to Utils.h/cpp. A large amount of work includes moving to the new namespace (`TerminalApp` --> `Microsoft::Terminal::Settings::Model`). Fixing the tests had its own complications. Testing required us to split up TSM into a DLL and LIB, similar to TermApp. Discussion on creating a non-local test variant can be found in #7743. Closes #885
2020-10-06 18:56:59 +02:00
std::vector<ActionAndArgs> TerminalPage::ConvertExecuteCommandlineToActions(const ExecuteCommandlineArgs& args)
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
{
::TerminalApp::AppCommandlineArgs appArgs;
if (appArgs.ParseArgs(args) == 0)
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
{
return appArgs.GetStartupActions();
Add support for running a `wt` commandline in the curent window WITH A KEYBINDING (#6537) ## Summary of the Pull Request Adds a execute commandline action (`wt`), which lets a user bind a key to a specific `wt` commandline. This commandline will get parsed and run _in the current window_. ## References * Related to #4472 * Related to #5400 - I need this for the commandline mode of the Command Palette * Related to #5970 ## PR Checklist * [x] Closes oh, there's not actually an issue for this. * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - yes it does ## Detailed Description of the Pull Request / Additional comments One important part of this change concerns how panes are initialized at runtime. We've had some persistent trouble with initializing multiple panes, because they rely on knowing how big they'll actually be, to be able to determine if they can split again. We previously worked around this by ignoring the size check when we were in "startup", processing an initial commandline. This PR however requires us to be able to know the initial size of a pane at runtime, but before the parents have necessarily been added to the tree, or had their renderer's set up. This led to the development of `Pane::PreCalculateCanSplit`, which is very highly similar to `Pane::PreCalculateAutoSplit`. This method attempts to figure out how big a pane _will_ take, before the parent has necessarily laid out. This also involves a small change to `TermControl`, because if its renderer hasn't been set up yet, it'll always think the font is `{0, fontHeight}`, which will let the Terminal keep splitting in the x direction. This change also makes the TermControl set up a renderer to get the real font size when it hasn't yet been initialized. ## Validation Steps Performed This was what the json blob I was using for testing evolved into ```json { "command": { "action":"wt", "commandline": "new-tab cmd.exe /k #work 15 ; split-pane cmd.exe /k #work 15 ; split-pane cmd.exe /k media-commandline ; new-tab powershell dev\\symbols.ps1 ; new-tab -p \"Ubuntu\" ; new-tab -p \"haunter.gif\" ; focus-tab -t 0", }, "keys": ["ctrl+shift+n"] } ``` I also added some tests. # TODO * [x] Creating a `{ "command": "wt" }` action without a commandline will spawn a new `wt.exe` process? - Probably should just do nothing for the empty string
2020-07-17 23:05:29 +02:00
}
return {};
}
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
void TerminalPage::_FocusActiveControl(IInspectable /*sender*/,
IInspectable /*eventArgs*/)
{
minor refactor: Move Tab management into its own file (#9629) I think we can all agree that `TerminalPage.cpp` is an unruly beast of a file. It's got everything. It does everything. It can sometimes be a bit hard to work with, because of simply how big it is. This PR tries to alleviate this by making `TerminalPage.cpp` just a little smaller. It does so by moving pretty much everything related to tab management into its own file, `TabManagement.cpp`. These methods that have moved are all the same as they were before, and they're still members of `TerminalPage`. But now they're all in one place. I tried to move all the references to `_tabs` in `TerminalPage.cpp`, but there's still a few that I left behind. Mostly because I felt that moving those would be too gnarly a code change for an otherwise simple cut&paste PR. There are a few new methods I introduced: * `_TabDragStarted` and `_TabDragCompleted`: These were lambdas before, promoted to full methods. * `_DismissTabContextMenus`: Remove all the right-click context menus from the tabs * `_FocusCurrentTab`: This one's a bit trickier, we were actually doing this in a few different places, so I tried consolidating. * `_HasMultipleTabs`: This doesn't need explaining. * `_RemoveAllTabs`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` * `_ResizeTabContent`: Really, just encapsulation for the sake of removing a `_tabs` from `TerminalPage.cpp` In the future, some enterprising young soul could try promoting that file to its own class, and hiding `_tabs` (and `_mruTabs`) inside it. Probably would need to take a reference to TerminalPage's `_tabView` and `_newTabButton`. I'm not doing that right now, because I already hate the idea of the ... > 920 additions and 847 deletions. ... I'm making you look at already. ## Other thoughts Some of the calls might be a little arbitrary - `_OpenNewTab` and `_CreateNewTabFromSettings` probably should stay in `TerminalPage`? Or at least elements of those might need to get split up better. Similarly `TerminalPage::_OpenSettingsUI` stayed in `TerminalPage.cpp`, but it does a lot of the same work as `_CreateNewTabFromSettings`. I'm not saying this is the definitive places for these methods - it's code we're working with, not stone ☺️
2021-03-29 21:53:39 +02:00
_FocusCurrentTab(false);
}
bool TerminalPage::FocusMode() const
{
return _isInFocusMode;
}
bool TerminalPage::Fullscreen() const
{
return _isFullscreen;
}
// Method Description:
// - Returns true if we're currently in "Always on top" mode. When we're in
// always on top mode, the window should be on top of all other windows.
// If multiple windows are all "always on top", they'll maintain their own
// z-order, with all the windows on top of all other non-topmost windows.
// Arguments:
// - <none>
// Return Value:
// - true if we should be in "always on top" mode
bool TerminalPage::AlwaysOnTop() const
{
return _isAlwaysOnTop;
}
HRESULT TerminalPage::_OnNewConnection(const ConptyConnection& connection)
{
// We need to be on the UI thread in order for _OpenNewTab to run successfully.
// HasThreadAccess will return true if we're currently on a UI thread and false otherwise.
// When we're on a COM thread, we'll need to dispatch the calls to the UI thread
// and wait on it hence the locking mechanism.
if (!Dispatcher().HasThreadAccess())
{
til::latch latch{ 1 };
HRESULT finalVal = S_OK;
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [&]() {
finalVal = _OnNewConnection(connection);
latch.count_down();
});
latch.wait();
return finalVal;
}
try
{
NewTerminalArgs newTerminalArgs;
newTerminalArgs.Commandline(connection.Commandline());
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
const auto settings{ TerminalSettings::CreateWithProfile(_settings, profile, *_bindings) };
_CreateNewTabWithProfileAndSettings(profile, settings, connection);
// Request a summon of this window to the foreground
_SummonWindowRequestedHandlers(*this, nullptr);
return S_OK;
}
CATCH_RETURN()
}
// Method Description:
// - Creates a settings UI tab and focuses it. If there's already a settings UI tab open,
// just focus the existing one.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_OpenSettingsUI()
{
// If we're holding the settings tab's switch command, don't create a new one, switch to the existing one.
if (!_settingsTab)
{
winrt::Microsoft::Terminal::Settings::Editor::MainPage sui{ _settings };
if (_hostingHwnd)
{
sui.SetHostingWindow(reinterpret_cast<uint64_t>(*_hostingHwnd));
}
Hook up the keybindings to the SUI, redux (#10121) ## Summary of the Pull Request This is a redux of #8882. From the original: > This is really similar to what we're doing with the `CommandPalette`. We're adding a ~~Preview~~`KeyDown` handler to the SUI `MainPage`, that connects to `TerminalPage::_HandleKey`. That allows the SUI a chance to search the keymap to dispatch actions for keybindings, similar to how the command palette does it. > > This also means it's now possible for the SUI to invoke _all_ the actions available to the Terminal. This includes the ones like `IncreaseFontSize`, which require a _Terminal_ to actually do something. So we have to make sure all the calls to `_GetActiveControl` actually check that the result is non-null before using it. > > A bunch of the actions do nothing now from a SUI tab, others behave _weird_. Like "Rename tab" / "Open Tab Renamer" do nothing. "Duplicate Tab" again does nothing - we try making a new settings tab, which just focuses the settings tab again. "Copy text" definitely does nothing, same with paste. I don't know why I thought this wouldn't work. I thought we'd have to do this in `PreviewKeyDown` or something, which led to [weirdness](https://github.com/microsoft/terminal/pull/8882#issuecomment-767088554). Turns out, we don't need it to be in `PreviewKeyDown`. It can just be in the SUI's `KeyDown`. ## References * Original: #8882 * Workaround was in #8885 ## PR Checklist * [x] Closes #8767 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments The special case handler from #8885 is no longer needed ## Validation Steps Performed * Switching tabs with Ctrl+Tab works * Command palette works * fullscreen, focus mode works * close window works * copy paste on Ctrl+C/V works, even when bound * Select all text in textboxes works * tab navigation through UI elements works
2021-05-24 21:18:38 +02:00
// GH#8767 - let unhandled keys in the SUI try to run commands too.
sui.KeyDown({ this, &TerminalPage::_KeyDownHandler });
sui.OpenJson([weakThis{ get_weak() }](auto&& /*s*/, winrt::Microsoft::Terminal::Settings::Model::SettingsTarget e) {
if (auto page{ weakThis.get() })
{
page->_LaunchSettings(e);
}
});
auto newTabImpl = winrt::make_self<SettingsTab>(sui);
// Add the new tab to the list of our tabs.
_tabs.Append(*newTabImpl);
_mruTabs.Append(*newTabImpl);
newTabImpl->SetDispatch(*_actionDispatch);
Introduce ActionMap to Terminal Settings Model (#9621) This entirely removes `KeyMapping` from the settings model, and builds on the work done in #9543 to consolidate all actions (key bindings and commands) into a unified data structure (`ActionMap`). ## References #9428 - Spec #6900 - Actions page Closes #7441 ## Detailed Description of the Pull Request / Additional comments The important thing here is to remember that we're shifting our philosophy of how to interact/represent actions. Prior to this, the actions arrays in the JSON would be deserialized twice: once for key bindings, and again for commands. By thinking of every entry in the relevant JSON as a `Command`, we can remove a lot of the context switching between working with a key binding vs a command palette item. #9543 allows us to make that shift. Given the work in that PR, we can now deserialize all of the relevant information from each JSON action item. This allows us to simplify `ActionMap::FromJson` to simply iterate over each JSON action item, deserialize it, and add it to our `ActionMap`. Internally, our `ActionMap` operates as discussed in #9428 by maintaining a `_KeyMap` that points to an action ID, and using that action ID to retrieve the `Command` from the `_ActionMap`. Adding actions to the `ActionMap` automatically accounts for name/key-chord collisions. A `NameMap` can be constructed when requested; this is for the Command Palette. Querying the `ActionMap` is fairly straightforward. Helper functions were needed to be able to distinguish an explicit unbinding vs the command not being found in the current layer. Internally, we store explicitly unbound names/key-chords as `ShortcutAction::Invalid` commands. However, we return `nullptr` when a query points to an unbound command. This is done to hide this complexity away from any caller. The command palette still needs special handling for nested and iterable commands. Thankfully, the expansion of iterable commands is performed on an `IMapView`, so we can just expose `NameMap` as a consolidation of `ActionMap`'s `NameMap` with its parents. The same can be said for exposing key chords in nested commands. ## Validation Steps Performed All local tests pass.
2021-05-05 06:50:13 +02:00
newTabImpl->SetActionMap(_settings.ActionMap());
// Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command.
_UpdateTabIndices();
// Don't capture a strong ref to the tab. If the tab is removed as this
// is called, we don't really care anymore about handling the event.
auto weakTab = make_weak(newTabImpl);
auto tabViewItem = newTabImpl->TabViewItem();
_tabView.TabItems().Append(tabViewItem);
tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick });
// When the tab requests close, try to close it (prompt for approval, if required)
newTabImpl->CloseRequested([weakTab, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
auto page{ weakThis.get() };
auto tab{ weakTab.get() };
if (page && tab)
{
page->_HandleCloseTabRequested(*tab);
}
});
// When the tab is closed, remove it from our list of tabs.
newTabImpl->Closed([tabViewItem, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
if (auto page{ weakThis.get() })
{
page->_settingsTab = nullptr;
page->_RemoveOnCloseRoutine(tabViewItem, page);
}
});
_settingsTab = *newTabImpl;
// This kicks off TabView::SelectionChanged, in response to which
// we'll attach the terminal's Xaml control to the Xaml root.
_tabView.SelectedItem(tabViewItem);
}
else
{
_tabView.SelectedItem(_settingsTab.TabViewItem());
}
}
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
// Method Description:
// - Returns a com_ptr to the implementation type of the given tab if it's a TerminalTab.
// If the tab is not a TerminalTab, returns nullptr.
// Arguments:
// - tab: the projected type of a Tab
// Return Value:
// - If the tab is a TerminalTab, a com_ptr to the implementation type.
// If the tab is not a TerminalTab, nullptr
winrt::com_ptr<TerminalTab> TerminalPage::_GetTerminalTabImpl(const TerminalApp::TabBase& tab)
Make Tab an unsealed runtimeclass (and rename it to TabBase) (#8153) In preparation for the Settings UI, we needed to make some changes to Tab to abstract out shared, common functionality between different types of tab. This is the result of that work. All code references to the settings have been removed or reverted. Contains changes from #8053, #7802. The messages below only make sense in the context of the Settings UI, which this pull request does not bring in. They do, however, provide valuable information. From #7802 (@leonMSFT): > This PR's goal was to add an option to the `OpenSettings` keybinding to > open the Settings UI in a tab. In order to implement that, a couple of > changes had to be made to `Tab`, specifically: > > - Introduce a tab interface named `ITab` > - Create/Rename two new Tab classes that implement `ITab` called > `SettingsTab` and `TerminalTab` > From #8053: > `TerminalTab` and `SettingsTab` share some implementation details. The > close submenu introduced in #7728 is a good example of functionality > that is consistent across all tabs. This PR transforms `ITab` from an > interface, into an [unsealed runtime class] to de-duplicate some > functionality. Most of the logic from `SettingsTab` was moved there > because I expect the default behavior of a tab to resemble the > `SettingsTab` over a `TerminalTab`. > > ## References > Verified that Close submenu work was transferred over (#7728, #7961, #8010). > > ## Validation Steps Performed > Check close submenu on first/last tab when multiple tabs are open. > > Closes #7969 > > [unsealed runtime class]: https://docs.microsoft.com/en-us/uwp/midl-3/intro#base-classes Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com> Co-authored-by: Leon Liang <lelian@microsoft.com> Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2020-11-04 19:15:05 +01:00
{
if (auto terminalTab = tab.try_as<TerminalApp::TerminalTab>())
{
winrt::com_ptr<TerminalTab> tabImpl;
tabImpl.copy_from(winrt::get_self<TerminalTab>(terminalTab));
return tabImpl;
}
else
{
return nullptr;
}
}
// Method Description:
// - Computes the delta for scrolling the tab's viewport.
// Arguments:
// - scrollDirection - direction (up / down) to scroll
// - rowsToScroll - the number of rows to scroll
// Return Value:
// - delta - Signed delta, where a negative value means scrolling up.
int TerminalPage::_ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll)
{
return scrollDirection == ScrollUp ? -1 * rowsToScroll : rowsToScroll;
}
// Method Description:
// - Reads system settings for scrolling (based on the step of the mouse scroll).
// Upon failure fallbacks to default.
// Return Value:
// - The number of rows to scroll or a magic value of WHEEL_PAGESCROLL
// indicating that we need to scroll an entire view height
uint32_t TerminalPage::_ReadSystemRowsToScroll()
{
uint32_t systemRowsToScroll;
if (!SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &systemRowsToScroll, 0))
{
LOG_LAST_ERROR();
// If SystemParametersInfoW fails, which it shouldn't, fall back to
// Windows' default value.
return DefaultRowsToScroll;
}
return systemRowsToScroll;
}
// Method Description:
// - Displays a dialog stating the "Touch Keyboard and Handwriting Panel
// Service" is disabled.
void TerminalPage::ShowKeyboardServiceWarning() const
{
if (!_IsMessageDismissed(InfoBarMessage::KeyboardServiceWarning))
{
if (const auto keyboardServiceWarningInfoBar = FindName(L"KeyboardServiceWarningInfoBar").try_as<MUX::Controls::InfoBar>())
{
keyboardServiceWarningInfoBar.IsOpen(true);
}
}
}
// Method Description:
// - Displays a info popup guiding the user into setting their default terminal.
void TerminalPage::ShowSetAsDefaultInfoBar() const
{
if (!CascadiaSettings::IsDefaultTerminalAvailable() || _IsMessageDismissed(InfoBarMessage::SetAsDefault))
{
return;
}
// If the user has already configured any terminal for hand-off we
// shouldn't inform them again about the possibility to do so.
if (CascadiaSettings::IsDefaultTerminalSet())
{
_DismissMessage(InfoBarMessage::SetAsDefault);
return;
}
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
{
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipPresented", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
infoBar.IsOpen(true);
}
}
// Function Description:
// - Helper function to get the OS-localized name for the "Touch Keyboard
// and Handwriting Panel Service". If we can't open up the service for any
// reason, then we'll just return the service's key, "TabletInputService".
// Return Value:
// - The OS-localized name for the TabletInputService
winrt::hstring _getTabletServiceName()
{
auto isUwp = false;
try
{
isUwp = ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Logic().IsUwp();
}
CATCH_LOG();
if (isUwp)
{
return winrt::hstring{ TabletInputServiceKey };
}
wil::unique_schandle hManager{ OpenSCManager(nullptr, nullptr, 0) };
if (LOG_LAST_ERROR_IF(!hManager.is_valid()))
{
return winrt::hstring{ TabletInputServiceKey };
}
DWORD cchBuffer = 0;
GetServiceDisplayName(hManager.get(), TabletInputServiceKey.data(), nullptr, &cchBuffer);
std::wstring buffer;
cchBuffer += 1; // Add space for a null
buffer.resize(cchBuffer);
if (LOG_LAST_ERROR_IF(!GetServiceDisplayName(hManager.get(),
TabletInputServiceKey.data(),
buffer.data(),
&cchBuffer)))
{
return winrt::hstring{ TabletInputServiceKey };
}
return winrt::hstring{ buffer };
}
// Method Description:
// - Return the fully-formed warning message for the
// "KeyboardServiceDisabled" InfoBar. This InfoBar is used to warn the user
// if the keyboard service is disabled, and uses the OS localization for
// the service's actual name. It's bound to the bar in XAML.
// Return Value:
// - The warning message, including the OS-localized service name.
winrt::hstring TerminalPage::KeyboardServiceDisabledText()
{
const winrt::hstring serviceName{ _getTabletServiceName() };
const winrt::hstring text{ fmt::format(std::wstring_view(RS_(L"KeyboardServiceWarningText")), serviceName) };
return text;
}
// Method Description:
// - Hides cursor if required
// Return Value:
// - <none>
void TerminalPage::_HidePointerCursorHandler(const IInspectable& /*sender*/, const IInspectable& /*eventArgs*/)
{
if (_shouldMouseVanish && !_isMouseHidden)
{
if (auto window{ CoreWindow::GetForCurrentThread() })
{
try
{
window.PointerCursor(nullptr);
_isMouseHidden = true;
}
CATCH_LOG();
}
}
}
// Method Description:
// - Restores cursor if required
// Return Value:
// - <none>
void TerminalPage::_RestorePointerCursorHandler(const IInspectable& /*sender*/, const IInspectable& /*eventArgs*/)
{
if (_isMouseHidden)
{
if (auto window{ CoreWindow::GetForCurrentThread() })
{
try
{
window.PointerCursor(_defaultPointerCursor);
_isMouseHidden = false;
}
CATCH_LOG();
}
}
}
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
// Method Description:
// - Update the RequestedTheme of the specified FrameworkElement and all its
// Parent elements. We need to do this so that we can actually theme all
// of the elements of the TeachingTip. See GH#9717
// Arguments:
// - element: The TeachingTip to set the theme on.
// Return Value:
// - <none>
void TerminalPage::_UpdateTeachingTipTheme(winrt::Windows::UI::Xaml::FrameworkElement element)
{
auto theme{ _settings.GlobalSettings().Theme() };
while (element)
{
element.RequestedTheme(theme);
element = element.Parent().try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
}
}
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
// Method Description:
// - Display the name and ID of this window in a TeachingTip. If the window
// has no name, the name will be presented as "<unnamed-window>".
// - This can be invoked by either:
// * An identifyWindow action, that displays the info only for the current
// window
// * An identifyWindows action, that displays the info for all windows.
// Arguments:
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget TerminalPage::IdentifyWindow()
{
auto weakThis{ get_weak() };
co_await winrt::resume_foreground(Dispatcher());
if (auto page{ weakThis.get() })
{
// If we haven't ever loaded the TeachingTip, then do so now and
// create the toast for it.
if (page->_windowIdToast == nullptr)
{
if (MUX::Controls::TeachingTip tip{ page->FindName(L"WindowIdToast").try_as<MUX::Controls::TeachingTip>() })
{
page->_windowIdToast = std::make_shared<Toast>(tip);
// Make sure to use the weak ref when setting up this
// callback.
tip.Closed({ page->get_weak(), &TerminalPage::_FocusActiveControl });
}
}
_UpdateTeachingTipTheme(WindowIdToast().try_as<winrt::Windows::UI::Xaml::FrameworkElement>());
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
if (page->_windowIdToast != nullptr)
{
page->_windowIdToast->Open();
}
}
}
// WindowName is a otherwise generic WINRT_OBSERVABLE_PROPERTY, but it needs
// to raise a PropertyChanged for WindowNameForDisplay, instead of
// WindowName.
winrt::hstring TerminalPage::WindowName() const noexcept
{
return _WindowName;
}
winrt::fire_and_forget TerminalPage::WindowName(const winrt::hstring& value)
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
{
Make the window name `_quake` special (#9785) ## Summary of the Pull Request This PR adds some special behavior to the window named "\_quake". * When creating the quake window, it ignores "initialRows" and "initialCols" and opens on the top half of the monitor. - It uses `initialPosition` to determine which monitor this is * It cannot be moved * It can only be vertically resized on the bottom border. * It's always in focus mode. - We should probably have an issue tracking "Allow showing tabs in focus mode"? Maybe? - This one element is maybe the one I'm least attached to When renaming a window to "\_quake", it adopts all those behaviors as well. It does not exit focus mode when leaving QM, nor does it resize back. That seemed unnecessary. ## References * As spec'ed in #9274 * See also #8888 ## PR Checklist * [x] In the pursuit of #653 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated, but I'm not gonna do any of that till quake mode is totally done. ## Detailed Description of the Pull Request / Additional comments Note that this doesn't do things like: * dropdown * global hotkey summon * summon to the current monitor * summon to the current desktop I'm doing #653 _very_ piecemeal, to try and make the PRs less egregious. ## Validation Steps Performed * validated that center on launch still works * validated that QM works on different monitors based on `initialPosition` * validated entering/exiting QM behaves as expected ## TODO! * [ ] When snapping the quake window between desktops with <kbd>win+shift+arrow</kbd>, the window doesn't horizontally re-size to the new monitor dimensions. It should.
2021-04-26 21:36:23 +02:00
const bool oldIsQuakeMode = IsQuakeWindow();
const bool changed = _WindowName != value;
if (changed)
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
{
_WindowName = value;
}
auto weakThis{ get_weak() };
// On the foreground thread, raise property changed notifications, and
// display the success toast.
co_await resume_foreground(Dispatcher());
if (auto page{ weakThis.get() })
{
if (changed)
{
page->_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"WindowName" });
page->_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"WindowNameForDisplay" });
// DON'T display the confirmation if this is the name we were
// given on startup!
if (page->_startupState == StartupState::Initialized)
{
page->IdentifyWindow();
Make the window name `_quake` special (#9785) ## Summary of the Pull Request This PR adds some special behavior to the window named "\_quake". * When creating the quake window, it ignores "initialRows" and "initialCols" and opens on the top half of the monitor. - It uses `initialPosition` to determine which monitor this is * It cannot be moved * It can only be vertically resized on the bottom border. * It's always in focus mode. - We should probably have an issue tracking "Allow showing tabs in focus mode"? Maybe? - This one element is maybe the one I'm least attached to When renaming a window to "\_quake", it adopts all those behaviors as well. It does not exit focus mode when leaving QM, nor does it resize back. That seemed unnecessary. ## References * As spec'ed in #9274 * See also #8888 ## PR Checklist * [x] In the pursuit of #653 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated, but I'm not gonna do any of that till quake mode is totally done. ## Detailed Description of the Pull Request / Additional comments Note that this doesn't do things like: * dropdown * global hotkey summon * summon to the current monitor * summon to the current desktop I'm doing #653 _very_ piecemeal, to try and make the PRs less egregious. ## Validation Steps Performed * validated that center on launch still works * validated that QM works on different monitors based on `initialPosition` * validated entering/exiting QM behaves as expected ## TODO! * [ ] When snapping the quake window between desktops with <kbd>win+shift+arrow</kbd>, the window doesn't horizontally re-size to the new monitor dimensions. It should.
2021-04-26 21:36:23 +02:00
// If we're entering quake mode, or leaving it
if (IsQuakeWindow() != oldIsQuakeMode)
{
// If we're entering Quake Mode from ~Focus Mode, then this will enter Focus Mode
// If we're entering Quake Mode from Focus Mode, then this will do nothing
// If we're leaving Quake Mode (we're already in Focus Mode), then this will do nothing
_SetFocusMode(true);
_IsQuakeWindowChangedHandlers(*this, nullptr);
}
}
}
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
}
}
// WindowId is a otherwise generic WINRT_OBSERVABLE_PROPERTY, but it needs
// to raise a PropertyChanged for WindowIdForDisplay, instead of
// WindowId.
uint64_t TerminalPage::WindowId() const noexcept
{
return _WindowId;
}
void TerminalPage::WindowId(const uint64_t& value)
{
if (_WindowId != value)
{
_WindowId = value;
Add support for renaming windows (#9662) ## Summary of the Pull Request This PR adds support for renaming windows. ![window-renaming-000](https://user-images.githubusercontent.com/18356694/113034344-9a30be00-9157-11eb-9443-975f3c294f56.gif) ![window-renaming-001](https://user-images.githubusercontent.com/18356694/113034452-b5033280-9157-11eb-9e35-e5ac80fef0bc.gif) It does so through two new actions: * `renameWindow` takes a `name` parameter, and attempts to set the window's name to the provided name. This is useful if you always want to hit <kbd>F3</kbd> and rename a window to "foo" (READ: probably not that useful) * `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a `TextBox`. When the user hits Ok, it'll request a rename for the provided value. This lets the user pick a new name for the window at runtime. In both cases, if there's already a window with that name, then the monarch will reject the rename, and pop a `Toast` in the window informing the user that the rename failed. Nifty! ## References * Builds on the toasts from #9523 * #5000 - process model megathread ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747 * [x] I work here * [x] Tests addded (and pass with the help of #9660) * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews. > PAIN: We can't immediately focus the textbox in the TeachingTip. It's > not technically focusable until it is opened. However, it doesn't > provide an even tto tell us when it is opened. That's tracked in > microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to > click on the text box manually. > We're also not using a ContentDialog for this, because in Xaml > Islands a text box in a ContentDialog won't recieve _any_ keypresses. > Fun! ## Validation Steps Performed I've been playing with ```json { "keys": "f1", "command": "identifyWindow" }, { "keys": "f2", "command": "identifyWindows" }, { "keys": "f3", "command": "openWindowRenamer" }, { "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } }, { "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } }, ``` and they seem to work as expected
2021-04-02 18:00:04 +02:00
_PropertyChangedHandlers(*this, WUX::Data::PropertyChangedEventArgs{ L"WindowIdForDisplay" });
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
}
}
Persist window layout cont. save multiple windows (#11083) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Continuation of https://github.com/microsoft/terminal/pull/10972 to handle multiple windows, requires that to be merged first. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Also closes #766 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] 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 * [x] Schema updated. * [ ] 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 <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments Rough changelog: Normally saving is triggered to occur every 30s, or sooner if a window is created/closed. The existing behavior of saving on last close is maintained to bypass that throttling. The automatic saving allows for crash recovery. Additionally all window layouts will be saved upon taking the `quit` action. For loading we will check if we are the first window, that there are any saved layouts, and if the setting is enabled, and then depending on if we were given command line args or startup actions. - create a new window for each saved layout, or - take the first layout for our self and then a new window for each other layout. This also saves the layout when the quit action is taken. Misc changes - A -s,--saved argument was added to the command line to facilitate opening all of the windows with the right settings. This also means that while a terminal session is running you can do wt -s idx to open a copy of window idx. There isn't a stable ordering of which idx each window gets saved as (it is whatever the iteration order of _peasants is), so it is just a cute hack for now. - All position calculation has been moved up to AppHost this does mean we need to awkwardly pass around positions in a couple of unexpected places, but no solution was perfect. - Renamed "Open tabs from a previous session" to "Open windows from a previous session". (not reflected in video below) - Now save runtime tab color and window names - Only enabled for non-elevated windows - Add some change tracking to ApplicationState <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ![output](https://user-images.githubusercontent.com/6185249/131163473-d649d204-a589-41ad-b9d9-c4c0528cb684.gif)
2021-09-27 23:18:39 +02:00
void TerminalPage::SetPersistedLayoutIdx(const uint32_t idx)
{
_loadFromPersistedLayoutIdx = idx;
}
Persist window layout on window close (#10972) This commit adds initial support for saving window layout on application close. Done: - Add user setting for if tabs should be maintained. - Added events to track the number of open windows for the monarch, and then save if you are the last window closing. - Saves layout when the user explicitly hits the "Close Window" button. - If the user manually closed all of their tabs (through the tab x button or through closing all panes on the tab) then remove any saved state. - Saves in the ApplicationState file a list of actions the terminal can perform to restore its layout and the window size/position information. - This saves an action to focus the correct pane, but this won't actually work without #10978. Note that if you have a pane zoomed, it does still zoom the correct pane, but when you unzoom it will have a different pane selected. Todo: - multiple windows? Right now it can only handle loading/saving one window. - PR #11083 will save multiple windows. - This also sometimes runs into the existing bug where multiple tabs appear to be focused on opening. Next Steps: - The business logic of when the save is triggered can be adjusted as necessary. - Right now I am taking the pragmatic approach and just saving the state as an array of objects, but only ever populate it with 1, that way saving multiple windows in the future could be added without breaking schema compatibility. Selfishly I'm hoping that handling multiple windows could be spun off into another pr/feature for now. - One possible thing that can maybe be done is that the commandline can be augmented with a "--saved ##" attribute that would load from the nth saved state if it exists. e.g. if there are 3 saved windows, on first load it can spawn three wt --saved {0,1,2} that would reopen the windows? This way there also exists a way to load a copy of a previous window (if it is in the saved state). - Is the application state something that is planned to be public/user editable? In theory the user could since it is just json, but I don't know what it buys them over just modifying their settings and startupActions. Validation Steps Performed: - The happy path: open terminal -> set setting to true -> close terminal -> reopen and see tabs. Tested with powershell/cmd/wsl windows. - That closing all panes/tabs on their own will remove the saved session. - Open multiple windows, close windows and confirm that the last window closed saves its state. The generated file stores a sequence of actions that will be executed to restore the terminal to its saved form. References #8324 This is also one of the items on microsoft/terminal#5000 Closes #766
2021-09-09 00:44:53 +02:00
void TerminalPage::SetNumberOfOpenWindows(const uint64_t num)
{
_numOpenWindows = num;
}
Add an action for identifying windows (#9523) ## Summary of the Pull Request This is a follow up to #9300. Now that we have names on our windows, it would be nice to see who is named what. So this adds two actions: * `identifyWindow`: This action will pop up a little toast (#8592) displaying the name and ID of the window, and is bound by default. ![identify-window-toast-000](https://user-images.githubusercontent.com/18356694/111529085-bf710580-872f-11eb-8880-b0b617596cfc.gif) * `identifyWindows`: This action will request that ALL windows pop up that toast. This is meant to feel like the "Identify" button on the Windows display settings. However, sometimes, it's wonky. ![teaching-tip-dismiss-001](https://user-images.githubusercontent.com/18356694/111529292-fe06c000-872f-11eb-8d4a-5688e4ce1175.gif) That's being tracked upstream on https://github.com/microsoft/microsoft-ui-xaml/issues/4382 Because it's so wonky, we won't bind that by default. Maybe if we get that fixed, then we'll change the default binding from `identifyWindow` to `identifyWindows` ## References ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-51431492 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments You may note that there are some macros to make interacting with lots and lots of actions easier. There's a lot of boilerplate whenever you need to make a new action, so I thought: "Can we make that easier?" Turns out you can make it a _LOT_ easier, but that work is still behind another PR after this one. Get excited
2021-03-30 18:08:03 +02:00
// Method Description:
// - Returns a label like "Window: 1234" for the ID of this window
// Arguments:
// - <none>
// Return Value:
// - a string for displaying the name of the window.
winrt::hstring TerminalPage::WindowIdForDisplay() const noexcept
{
return winrt::hstring{ fmt::format(L"{}: {}",
std::wstring_view(RS_(L"WindowIdLabel")),
_WindowId) };
}
// Method Description:
// - Returns a label like "<unnamed window>" when the window has no name, or the name of the window.
// Arguments:
// - <none>
// Return Value:
// - a string for displaying the name of the window.
winrt::hstring TerminalPage::WindowNameForDisplay() const noexcept
{
return _WindowName.empty() ?
winrt::hstring{ fmt::format(L"<{}>", RS_(L"UnnamedWindowName")) } :
_WindowName;
}
Add support for renaming windows (#9662) ## Summary of the Pull Request This PR adds support for renaming windows. ![window-renaming-000](https://user-images.githubusercontent.com/18356694/113034344-9a30be00-9157-11eb-9443-975f3c294f56.gif) ![window-renaming-001](https://user-images.githubusercontent.com/18356694/113034452-b5033280-9157-11eb-9e35-e5ac80fef0bc.gif) It does so through two new actions: * `renameWindow` takes a `name` parameter, and attempts to set the window's name to the provided name. This is useful if you always want to hit <kbd>F3</kbd> and rename a window to "foo" (READ: probably not that useful) * `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a `TextBox`. When the user hits Ok, it'll request a rename for the provided value. This lets the user pick a new name for the window at runtime. In both cases, if there's already a window with that name, then the monarch will reject the rename, and pop a `Toast` in the window informing the user that the rename failed. Nifty! ## References * Builds on the toasts from #9523 * #5000 - process model megathread ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747 * [x] I work here * [x] Tests addded (and pass with the help of #9660) * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews. > PAIN: We can't immediately focus the textbox in the TeachingTip. It's > not technically focusable until it is opened. However, it doesn't > provide an even tto tell us when it is opened. That's tracked in > microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to > click on the text box manually. > We're also not using a ContentDialog for this, because in Xaml > Islands a text box in a ContentDialog won't recieve _any_ keypresses. > Fun! ## Validation Steps Performed I've been playing with ```json { "keys": "f1", "command": "identifyWindow" }, { "keys": "f2", "command": "identifyWindows" }, { "keys": "f3", "command": "openWindowRenamer" }, { "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } }, { "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } }, ``` and they seem to work as expected
2021-04-02 18:00:04 +02:00
// Method Description:
// - Called when an attempt to rename the window has failed. This will open
// the toast displaying a message to the user that the attempt to rename
// the window has failed.
// - This will load the RenameFailedToast TeachingTip the first time it's called.
// Arguments:
// - <none>
// Return Value:
// - <none>
winrt::fire_and_forget TerminalPage::RenameFailed()
{
auto weakThis{ get_weak() };
co_await winrt::resume_foreground(Dispatcher());
if (auto page{ weakThis.get() })
{
// If we haven't ever loaded the TeachingTip, then do so now and
// create the toast for it.
if (page->_windowRenameFailedToast == nullptr)
{
if (MUX::Controls::TeachingTip tip{ page->FindName(L"RenameFailedToast").try_as<MUX::Controls::TeachingTip>() })
{
page->_windowRenameFailedToast = std::make_shared<Toast>(tip);
// Make sure to use the weak ref when setting up this
// callback.
tip.Closed({ page->get_weak(), &TerminalPage::_FocusActiveControl });
}
}
_UpdateTeachingTipTheme(RenameFailedToast().try_as<winrt::Windows::UI::Xaml::FrameworkElement>());
Add support for renaming windows (#9662) ## Summary of the Pull Request This PR adds support for renaming windows. ![window-renaming-000](https://user-images.githubusercontent.com/18356694/113034344-9a30be00-9157-11eb-9443-975f3c294f56.gif) ![window-renaming-001](https://user-images.githubusercontent.com/18356694/113034452-b5033280-9157-11eb-9e35-e5ac80fef0bc.gif) It does so through two new actions: * `renameWindow` takes a `name` parameter, and attempts to set the window's name to the provided name. This is useful if you always want to hit <kbd>F3</kbd> and rename a window to "foo" (READ: probably not that useful) * `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a `TextBox`. When the user hits Ok, it'll request a rename for the provided value. This lets the user pick a new name for the window at runtime. In both cases, if there's already a window with that name, then the monarch will reject the rename, and pop a `Toast` in the window informing the user that the rename failed. Nifty! ## References * Builds on the toasts from #9523 * #5000 - process model megathread ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747 * [x] I work here * [x] Tests addded (and pass with the help of #9660) * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews. > PAIN: We can't immediately focus the textbox in the TeachingTip. It's > not technically focusable until it is opened. However, it doesn't > provide an even tto tell us when it is opened. That's tracked in > microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to > click on the text box manually. > We're also not using a ContentDialog for this, because in Xaml > Islands a text box in a ContentDialog won't recieve _any_ keypresses. > Fun! ## Validation Steps Performed I've been playing with ```json { "keys": "f1", "command": "identifyWindow" }, { "keys": "f2", "command": "identifyWindows" }, { "keys": "f3", "command": "openWindowRenamer" }, { "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } }, { "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } }, ``` and they seem to work as expected
2021-04-02 18:00:04 +02:00
if (page->_windowRenameFailedToast != nullptr)
{
page->_windowRenameFailedToast->Open();
}
}
}
// Method Description:
// - Called when the user hits the "Ok" button on the WindowRenamer TeachingTip.
// - Will raise an event that will bubble up to the monarch, asking if this
// name is acceptable.
// - If it is, we'll eventually get called back in TerminalPage::WindowName(hstring).
// - If not, then TerminalPage::RenameFailed will get called.
// Arguments:
// - <unused>
// Return Value:
// - <none>
void TerminalPage::_WindowRenamerActionClick(const IInspectable& /*sender*/,
const IInspectable& /*eventArgs*/)
{
auto newName = WindowRenamerTextBox().Text();
_RequestWindowRename(newName);
}
void TerminalPage::_RequestWindowRename(const winrt::hstring& newName)
{
auto request = winrt::make<implementation::RenameWindowRequestedArgs>(newName);
// The WindowRenamer is _not_ a Toast - we want it to stay open until
// the user dismisses it.
if (WindowRenamer())
{
WindowRenamer().IsOpen(false);
}
Add support for renaming windows (#9662) ## Summary of the Pull Request This PR adds support for renaming windows. ![window-renaming-000](https://user-images.githubusercontent.com/18356694/113034344-9a30be00-9157-11eb-9443-975f3c294f56.gif) ![window-renaming-001](https://user-images.githubusercontent.com/18356694/113034452-b5033280-9157-11eb-9e35-e5ac80fef0bc.gif) It does so through two new actions: * `renameWindow` takes a `name` parameter, and attempts to set the window's name to the provided name. This is useful if you always want to hit <kbd>F3</kbd> and rename a window to "foo" (READ: probably not that useful) * `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a `TextBox`. When the user hits Ok, it'll request a rename for the provided value. This lets the user pick a new name for the window at runtime. In both cases, if there's already a window with that name, then the monarch will reject the rename, and pop a `Toast` in the window informing the user that the rename failed. Nifty! ## References * Builds on the toasts from #9523 * #5000 - process model megathread ## PR Checklist * [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747 * [x] I work here * [x] Tests addded (and pass with the help of #9660) * [ ] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews. > PAIN: We can't immediately focus the textbox in the TeachingTip. It's > not technically focusable until it is opened. However, it doesn't > provide an even tto tell us when it is opened. That's tracked in > microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to > click on the text box manually. > We're also not using a ContentDialog for this, because in Xaml > Islands a text box in a ContentDialog won't recieve _any_ keypresses. > Fun! ## Validation Steps Performed I've been playing with ```json { "keys": "f1", "command": "identifyWindow" }, { "keys": "f2", "command": "identifyWindows" }, { "keys": "f3", "command": "openWindowRenamer" }, { "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } }, { "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } }, ``` and they seem to work as expected
2021-04-02 18:00:04 +02:00
_RenameWindowRequestedHandlers(*this, request);
// We can't just use request.Successful here, because the handler might
// (will) be handling this asynchronously, so when control returns to
// us, this hasn't actually been handled yet. We'll get called back in
// RenameFailed if this fails.
//
// Theoretically we could do a IAsyncOperation<RenameWindowResult> kind
// of thing with co_return winrt::make<RenameWindowResult>(false).
}
// Method Description:
// - Manually handle Enter and Escape for committing and dismissing a window
// rename. This is highly similar to the TabHeaderControl's KeyUp handler.
// Arguments:
// - e: the KeyRoutedEventArgs describing the key that was released
// Return Value:
// - <none>
void TerminalPage::_WindowRenamerKeyUp(const IInspectable& sender,
winrt::Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
{
if (e.OriginalKey() == Windows::System::VirtualKey::Enter)
{
// User is done making changes, close the rename box
_WindowRenamerActionClick(sender, nullptr);
}
else if (e.OriginalKey() == Windows::System::VirtualKey::Escape)
{
// User wants to discard the changes they made
WindowRenamerTextBox().Text(WindowName());
WindowRenamer().IsOpen(false);
}
}
Enable previewing the color scheme in the command palette (#9794) ## Summary of the Pull Request Allow schemes to be previewed as the user hovers over them in the Command Palette. ![preview-set-color-scheme](https://user-images.githubusercontent.com/18356694/114557761-9a3cbd80-9c2f-11eb-987f-eb0c89ee1fa6.gif) ## References * Branched off of #8392, which is why the commit history is so polluted. 330a8e8 : 544b2fd has the interesting commits * #5400: cmdpal megathread ### Potential follow-ups * changing the font size * changing the font face * changing the opacity of acrylic ## PR Checklist * [x] Closes #6689, a last straggling FHL PR * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated - I don't think so ## Detailed Description of the Pull Request / Additional comments This works by inserting a "preview" `TerminalSettings` into the settings hierarchy, before the `TermControl`'s runtime settings, and after the ones from the actual `CascadiaSettings`. This allows us to modify that preview settings object, then discard it when we're done with the preview. This could also be used for other settings in the future - I built it to be extensible to other `ShortcutAction`s, though I haven't implemented those yet. ## Validation Steps Performed * Select a colorscheme - it becomes the active one * `colortool -x <scheme>` after selecting a scheme - colortool overrides the selected scheme * Select a colorscheme after a `colortool -x <scheme>` after selecting a scheme - the scheme in the palette becomes the active one * Pressing <kbd>esc</kbd> at any point to dismiss the command palette - scheme returns to the previous one * reloading the settings - returns to the scheme in the settings
2021-04-21 22:35:06 +02:00
Make the window name `_quake` special (#9785) ## Summary of the Pull Request This PR adds some special behavior to the window named "\_quake". * When creating the quake window, it ignores "initialRows" and "initialCols" and opens on the top half of the monitor. - It uses `initialPosition` to determine which monitor this is * It cannot be moved * It can only be vertically resized on the bottom border. * It's always in focus mode. - We should probably have an issue tracking "Allow showing tabs in focus mode"? Maybe? - This one element is maybe the one I'm least attached to When renaming a window to "\_quake", it adopts all those behaviors as well. It does not exit focus mode when leaving QM, nor does it resize back. That seemed unnecessary. ## References * As spec'ed in #9274 * See also #8888 ## PR Checklist * [x] In the pursuit of #653 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated, but I'm not gonna do any of that till quake mode is totally done. ## Detailed Description of the Pull Request / Additional comments Note that this doesn't do things like: * dropdown * global hotkey summon * summon to the current monitor * summon to the current desktop I'm doing #653 _very_ piecemeal, to try and make the PRs less egregious. ## Validation Steps Performed * validated that center on launch still works * validated that QM works on different monitors based on `initialPosition` * validated entering/exiting QM behaves as expected ## TODO! * [ ] When snapping the quake window between desktops with <kbd>win+shift+arrow</kbd>, the window doesn't horizontally re-size to the new monitor dimensions. It should.
2021-04-26 21:36:23 +02:00
bool TerminalPage::IsQuakeWindow() const noexcept
{
return WindowName() == QuakeWindowName;
}
// Method Description:
// - This function stops people from duplicating the base profile, because
// it gets ~ ~ weird ~ ~ when they do. Remove when TODO GH#5047 is done.
Profile TerminalPage::GetClosestProfileForDuplicationOfProfile(const Profile& profile) const noexcept
{
if (profile == _settings.ProfileDefaults())
{
return _settings.FindProfile(_settings.GlobalSettings().DefaultProfile());
}
return profile;
}
// Method Description:
// - Handles the change of connection state.
// If the connection state is failure show information bar suggesting to configure termination behavior
// (unless user asked not to show this message again)
// Arguments:
// - sender: the ICoreState instance containing the connection state
// Return Value:
// - <none>
winrt::fire_and_forget TerminalPage::_ConnectionStateChangedHandler(const IInspectable& sender, const IInspectable& /*args*/) const
{
if (const auto coreState{ sender.try_as<winrt::Microsoft::Terminal::Control::ICoreState>() })
{
const auto newConnectionState = coreState.ConnectionState();
if (newConnectionState == ConnectionState::Failed && !_IsMessageDismissed(InfoBarMessage::CloseOnExitInfo))
{
co_await winrt::resume_foreground(Dispatcher());
if (const auto infoBar = FindName(L"CloseOnExitInfoBar").try_as<MUX::Controls::InfoBar>())
{
infoBar.IsOpen(true);
}
}
}
}
// Method Description:
// - Persists the user's choice not to show information bar guiding to configure termination behavior.
// Then hides this information buffer.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_CloseOnExitInfoDismissHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/) const
{
_DismissMessage(InfoBarMessage::CloseOnExitInfo);
if (const auto infoBar = FindName(L"CloseOnExitInfoBar").try_as<MUX::Controls::InfoBar>())
{
infoBar.IsOpen(false);
}
}
// Method Description:
// - Persists the user's choice not to show information bar warning about "Touch keyboard and Handwriting Panel Service" disabled
// Then hides this information buffer.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_KeyboardServiceWarningInfoDismissHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/) const
{
_DismissMessage(InfoBarMessage::KeyboardServiceWarning);
if (const auto infoBar = FindName(L"KeyboardServiceWarningInfoBar").try_as<MUX::Controls::InfoBar>())
{
infoBar.IsOpen(false);
}
}
// Method Description:
// - Persists the user's choice not to show the information bar warning about "Windows Terminal can be set as your default terminal application"
// Then hides this information buffer.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalPage::_SetAsDefaultDismissHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
_DismissMessage(InfoBarMessage::SetAsDefault);
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
{
infoBar.IsOpen(false);
}
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipDismissed", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
_FocusCurrentTab(true);
}
// Method Description:
// - Dismisses the Default Terminal tip and opens the settings.
void TerminalPage::_SetAsDefaultOpenSettingsHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
if (const auto infoBar = FindName(L"SetAsDefaultInfoBar").try_as<MUX::Controls::InfoBar>())
{
infoBar.IsOpen(false);
}
TraceLoggingWrite(g_hTerminalAppProvider, "SetAsDefaultTipInteracted", TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
_OpenSettingsUI();
}
// Method Description:
// - Checks whether information bar message was dismissed earlier (in the application state)
// Arguments:
// - message: message to look for in the state
// Return Value:
// - true, if the message was dismissed
bool TerminalPage::_IsMessageDismissed(const InfoBarMessage& message)
{
if (const auto dismissedMessages{ ApplicationState::SharedInstance().DismissedMessages() })
{
for (const auto& dismissedMessage : dismissedMessages)
{
if (dismissedMessage == message)
{
return true;
}
}
}
return false;
}
// Method Description:
// - Persists the user's choice to dismiss information bar message (in application state)
// Arguments:
// - message: message to dismiss
// Return Value:
// - <none>
void TerminalPage::_DismissMessage(const InfoBarMessage& message)
{
const auto applicationState = ApplicationState::SharedInstance();
std::vector<InfoBarMessage> messages;
if (const auto values = applicationState.DismissedMessages())
{
messages.resize(values.Size());
values.GetMany(0, messages);
}
if (std::none_of(messages.begin(), messages.end(), [&](const auto& m) { return m == message; }))
{
messages.emplace_back(message);
}
applicationState.DismissedMessages(std::move(messages));
}
}