2019-07-09 23:47:30 +02:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "TerminalPage.h"
|
2019-09-04 23:34:06 +02:00
|
|
|
#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"
|
2019-07-09 23:47:30 +02:00
|
|
|
|
2019-11-01 23:47:05 +01:00
|
|
|
#include <LibraryResources.h>
|
|
|
|
|
2019-07-09 23:47:30 +02:00
|
|
|
#include "TerminalPage.g.cpp"
|
2020-05-27 19:42:49 +02:00
|
|
|
#include <winrt/Windows.Storage.h>
|
2019-09-04 23:34:06 +02:00
|
|
|
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
|
2019-07-09 23:47:30 +02:00
|
|
|
|
2019-10-15 07:41:43 +02:00
|
|
|
#include "TabRowControl.h"
|
2020-05-04 22:57:12 +02:00
|
|
|
#include "ColorHelper.h"
|
2020-03-26 23:33:47 +01:00
|
|
|
#include "DebugTapConnection.h"
|
2020-12-11 22:34:57 +01:00
|
|
|
#include "SettingsTab.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
|
|
|
|
2019-07-09 23:47:30 +02:00
|
|
|
using namespace winrt;
|
2020-04-17 19:15:20 +02:00
|
|
|
using namespace winrt::Windows::Foundation::Collections;
|
2019-09-04 23:34:06 +02:00
|
|
|
using namespace winrt::Windows::UI::Xaml;
|
2020-07-01 21:43:28 +02:00
|
|
|
using namespace winrt::Windows::UI::Xaml::Controls;
|
2019-09-04 23:34:06 +02:00
|
|
|
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;
|
|
|
|
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
|
|
|
using namespace winrt::Microsoft::Terminal::TerminalConnection;
|
2020-10-06 18:56:59 +02:00
|
|
|
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
2019-09-04 23:34:06 +02:00
|
|
|
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;
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
namespace winrt
|
|
|
|
{
|
|
|
|
namespace MUX = Microsoft::UI::Xaml;
|
2019-10-15 07:41:43 +02:00
|
|
|
namespace WUX = Windows::UI::Xaml;
|
2019-09-04 23:34:06 +02:00
|
|
|
using IInspectable = Windows::Foundation::IInspectable;
|
|
|
|
}
|
2019-07-09 23:47:30 +02:00
|
|
|
|
|
|
|
namespace winrt::TerminalApp::implementation
|
|
|
|
{
|
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>() },
|
2021-01-19 23:18:10 +01:00
|
|
|
_mruTabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
|
2020-11-30 20:51:42 +01:00
|
|
|
_startupActions{ winrt::single_threaded_vector<ActionAndArgs>() },
|
|
|
|
_hostingHwnd{}
|
2019-07-09 23:47:30 +02:00
|
|
|
{
|
2019-07-13 00:21:45 +02:00
|
|
|
InitializeComponent();
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
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.
|
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 there's a keybinding that's bound to exactly this command,
|
|
|
|
// then get the string for that keychord and display it as a
|
|
|
|
// part of the command in the UI. Each Command's KeyChordText is
|
|
|
|
// unset by default, so we don't need to worry about clearing it
|
|
|
|
// if there isn't a key associated with it.
|
2020-09-14 22:38:56 +02:00
|
|
|
auto keyChord{ settings.KeyMap().GetKeyBindingForActionWithArgs(command.Action()) };
|
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
|
|
|
|
|
|
|
if (keyChord)
|
|
|
|
{
|
|
|
|
command.KeyChordText(KeyChordSerialization::ToString(keyChord));
|
|
|
|
}
|
|
|
|
if (command.HasNestedCommands())
|
|
|
|
{
|
|
|
|
_recursiveUpdateCommandKeybindingLabels(settings, command.NestedCommands());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-06 18:56:59 +02:00
|
|
|
winrt::fire_and_forget TerminalPage::SetSettings(CascadiaSettings settings, bool needRefreshUI)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
_settings = settings;
|
|
|
|
if (needRefreshUI)
|
|
|
|
{
|
|
|
|
_RefreshUIForSettingsReload();
|
|
|
|
}
|
2020-06-26 22:38:02 +02:00
|
|
|
|
2020-10-27 02:19:52 +01:00
|
|
|
// Upon settings update we reload the system settings for scrolling as well.
|
|
|
|
// TODO: consider reloading this value periodically.
|
|
|
|
_systemRowsToScroll = _ReadSystemRowsToScroll();
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
auto weakThis{ get_weak() };
|
|
|
|
co_await winrt::resume_foreground(Dispatcher());
|
|
|
|
if (auto page{ weakThis.get() })
|
|
|
|
{
|
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
|
|
|
_UpdateCommandsForPalette();
|
2021-01-08 00:09:16 +01:00
|
|
|
CommandPalette().SetKeyMap(_settings.KeyMap());
|
2020-06-26 22:38:02 +02:00
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void TerminalPage::Create()
|
|
|
|
{
|
|
|
|
// Hookup the key bindings
|
2020-09-14 22:38:56 +02:00
|
|
|
_HookupKeyBindings(_settings.KeyMap());
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
_tabContent = this->TabContent();
|
|
|
|
_tabRow = this->TabRow();
|
|
|
|
_tabView = _tabRow.TabView();
|
2019-11-08 18:27:20 +01:00
|
|
|
_rearranging = false;
|
|
|
|
|
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 isElevated = false;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// GH#3581 - There's a platform limitation that causes us to crash when we rearrange tabs.
|
|
|
|
// Xaml tries to send a drag visual (to wit: a screenshot) to the drag hosting process,
|
|
|
|
// but that process is running at a different IL than us.
|
|
|
|
// For now, we're disabling elevated drag.
|
2020-04-27 18:17:19 +02:00
|
|
|
isElevated = ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Logic().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
|
|
|
}
|
|
|
|
CATCH_LOG();
|
|
|
|
|
2021-02-05 01:44:17 +01:00
|
|
|
_tabRow.PointerMoved({ this, &TerminalPage::_RestorePointerCursorHandler });
|
|
|
|
|
2020-03-11 16:52:09 +01:00
|
|
|
_tabView.CanReorderTabs(!isElevated);
|
|
|
|
_tabView.CanDragTabs(!isElevated);
|
|
|
|
|
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
|
|
|
_tabView.TabDragStarting([weakThis{ get_weak() }](auto&& /*o*/, auto&& /*a*/) {
|
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() })
|
2019-11-08 18:27:20 +01:00
|
|
|
{
|
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
|
|
|
page->_rearranging = true;
|
|
|
|
page->_rearrangeFrom = std::nullopt;
|
|
|
|
page->_rearrangeTo = std::nullopt;
|
2019-11-08 18:27:20 +01:00
|
|
|
}
|
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
|
|
|
});
|
|
|
|
|
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
|
|
|
_tabView.TabDragCompleted([weakThis{ get_weak() }](auto&& /*o*/, auto&& /*a*/) {
|
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() })
|
|
|
|
{
|
|
|
|
auto& from{ page->_rearrangeFrom };
|
|
|
|
auto& to{ page->_rearrangeTo };
|
2019-11-08 18:27:20 +01:00
|
|
|
|
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 (from.has_value() && to.has_value() && to != from)
|
|
|
|
{
|
|
|
|
auto& tabs{ page->_tabs };
|
2020-02-04 22:51:11 +01:00
|
|
|
auto tab = tabs.GetAt(from.value());
|
|
|
|
tabs.RemoveAt(from.value());
|
|
|
|
tabs.InsertAt(to.value(), tab);
|
2020-09-18 02:13:11 +02:00
|
|
|
page->_UpdateTabIndices();
|
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
|
|
|
}
|
|
|
|
|
|
|
|
page->_rearranging = false;
|
|
|
|
from = std::nullopt;
|
|
|
|
to = std::nullopt;
|
|
|
|
}
|
2019-11-08 18:27:20 +01:00
|
|
|
});
|
2019-10-15 07:41:43 +02:00
|
|
|
|
|
|
|
auto tabRowImpl = winrt::get_self<implementation::TabRowControl>(_tabRow);
|
|
|
|
_newTabButton = tabRowImpl->NewTabButton();
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-09-09 22:49:53 +02:00
|
|
|
if (_settings.GlobalSettings().ShowTabsInTitlebar())
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 22:51:38 +01:00
|
|
|
// Hookup our event handlers to the ShortcutActionDispatch
|
|
|
|
_RegisterActionCallbacks();
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
//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() })
|
|
|
|
{
|
2020-07-31 03:07:47 +02:00
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Check for DebugTap
|
2020-09-09 22:49:53 +02:00
|
|
|
bool debugTap = page->_settings.GlobalSettings().DebugFeaturesEnabled() &&
|
2020-07-31 03:07:47 +02:00
|
|
|
WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
|
|
|
|
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
|
|
|
|
|
|
|
|
if (altPressed && !debugTap)
|
|
|
|
{
|
2020-10-06 18:56:59 +02:00
|
|
|
page->_SplitPane(SplitState::Automatic,
|
|
|
|
SplitType::Manual,
|
Add `size` param to `splitPane` action, `split-pane` subcommand (#8543)
## Summary of the Pull Request
Adds a `size` parameter to `splitPane`. This takes a `float`, and specifies the portion of the parent pane that should be used to create the new one.
This also adds the param to the `split-pane` subcommand.
### Examples
| commandline | result |
| -- | -- |
| `wt ; sp -s .25` | ![image](https://user-images.githubusercontent.com/18356694/101784317-fb595680-3ac0-11eb-8248-782dc61957cf.png) |
| `wt ; sp -s .8` | ![image](https://user-images.githubusercontent.com/18356694/101784442-20e66000-3ac1-11eb-8f9b-fb45a73c9334.png) |
| `wt ; sp -s .8 ; sp -H -s .3` | ![image](https://user-images.githubusercontent.com/18356694/101784552-470c0000-3ac1-11eb-9deb-df37aaa36f01.png) |
## PR Checklist
* [x] Closes #6298
* [x] I work here
* [x] Tests added/passed
* [x] Docs PR: MicrosoftDocs/terminal#208
## Detailed Description of the Pull Request / Additional comments
I went with `size`, `--size,-s` rather than `percent`, because the arg is the (0,1) version of the size, not the (0%,100%) version.
## Validation Steps Performed
Added actions, played with the commandline, ran tests
2020-12-18 04:51:53 +01:00
|
|
|
0.5f,
|
2020-07-31 03:07:47 +02:00
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
page->_OpenNewTab(nullptr);
|
|
|
|
}
|
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
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
});
|
|
|
|
_tabView.SelectionChanged({ this, &TerminalPage::_OnTabSelectionChanged });
|
2019-10-15 07:41:43 +02:00
|
|
|
_tabView.TabCloseRequested({ this, &TerminalPage::_OnTabCloseRequested });
|
|
|
|
_tabView.TabItemsChanged({ this, &TerminalPage::_OnTabItemsChanged });
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
_CreateNewTabFlyout();
|
2020-01-27 16:34:12 +01:00
|
|
|
|
2020-01-10 01:16:54 +01:00
|
|
|
_UpdateTabWidthMode();
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
_tabContent.SizeChanged({ this, &TerminalPage::_OnContentSizeChanged });
|
2020-01-27 16:34:12 +01:00
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
_CommandPaletteClosed(nullptr, nullptr);
|
|
|
|
}
|
|
|
|
});
|
2020-12-10 01:36:28 +01:00
|
|
|
CommandPalette().DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested });
|
|
|
|
CommandPalette().CommandLineExecutionRequested({ this, &TerminalPage::_OnCommandLineExecutionRequested });
|
|
|
|
CommandPalette().SwitchToTabRequested({ this, &TerminalPage::_OnSwitchToTabRequested });
|
2020-06-26 22:38:02 +02:00
|
|
|
|
2020-10-10 01:06:40 +02:00
|
|
|
// 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 });
|
2020-11-02 19:51:29 +01:00
|
|
|
|
|
|
|
_isAlwaysOnTop = _settings.GlobalSettings().AlwaysOnTop();
|
2021-01-21 02:17:59 +01:00
|
|
|
|
|
|
|
// Setup mouse vanish attributes
|
|
|
|
SystemParametersInfoW(SPI_GETMOUSEVANISH, 0, &_shouldMouseVanish, false);
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
_defaultPointerCursor = CoreWindow::GetForCurrentThread().PointerCursor();
|
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
|
|
|
}
|
|
|
|
|
2020-12-10 01:36:28 +01: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)
|
|
|
|
{
|
|
|
|
const auto& actionAndArgs = command.Action();
|
|
|
|
_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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - This method is called once a tab was selected in tab switcher
|
|
|
|
// We'll use this event to select the relevant tab
|
|
|
|
// Arguments:
|
|
|
|
// - tab - tab to select
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void TerminalPage::_OnSwitchToTabRequested(const IInspectable& /*sender*/, const winrt::TerminalApp::TabBase& tab)
|
|
|
|
{
|
|
|
|
uint32_t index{};
|
|
|
|
if (_tabs.IndexOf(tab, index))
|
|
|
|
{
|
|
|
|
_SelectTab(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
2020-01-27 16:34:12 +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
|
|
|
_startupState = StartupState::InStartup;
|
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 (_startupActions.Size() == 0)
|
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
|
|
|
{
|
|
|
|
_OpenNewTab(nullptr);
|
2020-05-28 18:53:01 +02:00
|
|
|
|
|
|
|
_CompleteInitialization();
|
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
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
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
|
|
|
ProcessStartupActions(_startupActions, true);
|
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
|
|
|
}
|
2020-01-27 16:34:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2020-01-27 16:34:12 +01:00
|
|
|
// 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.
|
2020-01-27 16:34:12 +01:00
|
|
|
// 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,
|
|
|
|
const bool initial)
|
2020-01-27 16:34:12 +01:00
|
|
|
{
|
|
|
|
// If there are no actions left, do nothing.
|
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 (actions.Size() == 0)
|
2020-01-27 16:34:12 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
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);
|
2020-01-27 16:34:12 +01:00
|
|
|
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
|
|
|
|
{
|
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
|
|
|
}
|
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)
|
|
|
|
{
|
2020-05-28 18:53:01 +02:00
|
|
|
_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);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
2020-03-27 22:00:32 +01:00
|
|
|
// - 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()
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-07-01 21:43:28 +02:00
|
|
|
if (auto presenter{ _dialogPresenter.get() })
|
|
|
|
{
|
|
|
|
presenter.ShowDialog(FindName(L"AboutDialog").try_as<WUX::Controls::ContentDialog>());
|
|
|
|
}
|
2020-03-27 22:00:32 +01:00
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-03-27 22:00:32 +01:00
|
|
|
winrt::hstring TerminalPage::ApplicationDisplayName()
|
|
|
|
{
|
2020-10-06 18:56:59 +02:00
|
|
|
return CascadiaSettings::ApplicationDisplayName();
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-03-27 22:00:32 +01:00
|
|
|
winrt::hstring TerminalPage::ApplicationVersion()
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-10-06 18:56:59 +02:00
|
|
|
return CascadiaSettings::ApplicationVersion();
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-05-01 00:06:13 +02:00
|
|
|
void TerminalPage::_ThirdPartyNoticesOnClick(const IInspectable& /*sender*/, const Windows::UI::Xaml::RoutedEventArgs& /*eventArgs*/)
|
2020-04-28 22:22:44 +02:00
|
|
|
{
|
2020-05-01 00:06:13 +02:00
|
|
|
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);
|
2020-04-28 22:22:44 +02:00
|
|
|
}
|
|
|
|
|
2019-09-17 07:43:27 +02:00
|
|
|
// 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
|
2020-02-10 21:40:01 +01:00
|
|
|
// that more than 1 tab is opened, and once the user clicks the OK button, remove
|
2019-09-17 07:43:27 +02:00
|
|
|
// 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
|
2020-11-20 18:40:33 +01:00
|
|
|
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowCloseWarningDialog()
|
2019-09-17 07:43:27 +02:00
|
|
|
{
|
2020-07-01 21:43:28 +02:00
|
|
|
if (auto presenter{ _dialogPresenter.get() })
|
|
|
|
{
|
2020-11-20 18:40:33 +01:00
|
|
|
co_return co_await presenter.ShowDialog(FindName(L"CloseAllDialog").try_as<WUX::Controls::ContentDialog>());
|
2020-07-01 21:43:28 +02:00
|
|
|
}
|
2020-11-20 18:40:33 +01:00
|
|
|
co_return ContentDialogResult::None;
|
2020-07-01 21:43:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
2019-09-17 07:43:27 +02:00
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// 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, feedback
|
|
|
|
void TerminalPage::_CreateNewTabFlyout()
|
|
|
|
{
|
2019-10-15 07:41:43 +02:00
|
|
|
auto newTabFlyout = WUX::Controls::MenuFlyout{};
|
2020-09-14 22:38:56 +02:00
|
|
|
auto keyBindings = _settings.KeyMap();
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-09-09 22:49:53 +02:00
|
|
|
const auto defaultProfileGuid = _settings.GlobalSettings().DefaultProfile();
|
2019-09-04 23:34:06 +02:00
|
|
|
// the number of profiles should not change in the loop for this to work
|
2020-10-28 17:22:26 +01:00
|
|
|
auto const profileCount = gsl::narrow_cast<int>(_settings.ActiveProfiles().Size());
|
2019-09-04 23:34:06 +02:00
|
|
|
for (int profileIndex = 0; profileIndex < profileCount; profileIndex++)
|
|
|
|
{
|
2020-10-28 17:22:26 +01:00
|
|
|
const auto profile = _settings.ActiveProfiles().GetAt(profileIndex);
|
2019-10-15 07:41:43 +02:00
|
|
|
auto profileMenuItem = WUX::Controls::MenuFlyoutItem{};
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-08-20 23:58:13 +02:00
|
|
|
// 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
|
2020-10-06 18:56:59 +02:00
|
|
|
NewTerminalArgs newTerminalArgs{ profileIndex };
|
|
|
|
NewTabArgs newTabArgs{ newTerminalArgs };
|
|
|
|
ActionAndArgs actionAndArgs{ ShortcutAction::NewTab, newTabArgs };
|
|
|
|
auto profileKeyChord{ keyBindings.GetKeyBindingForActionWithArgs(actionAndArgs) };
|
2020-08-20 23:58:13 +02:00
|
|
|
|
|
|
|
// make sure we find one to display
|
|
|
|
if (profileKeyChord)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-08-20 23:58:13 +02:00
|
|
|
_SetAcceleratorForMenuItem(profileMenuItem, profileKeyChord);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-08-28 03:09:22 +02:00
|
|
|
auto profileName = profile.Name();
|
|
|
|
profileMenuItem.Text(profileName);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
// If there's an icon set for this profile, set it as the icon for
|
|
|
|
// this flyout item.
|
2020-10-08 20:29:04 +02:00
|
|
|
if (!profile.Icon().empty())
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-10-08 20:29:04 +02:00
|
|
|
const auto iconSource{ IconPathConverter().IconSourceWUX(profile.Icon()) };
|
2019-10-15 07:41:43 +02:00
|
|
|
|
|
|
|
WUX::Controls::IconSourceElement iconElement;
|
|
|
|
iconElement.IconSource(iconSource);
|
|
|
|
profileMenuItem.Icon(iconElement);
|
2020-03-05 23:32:46 +01:00
|
|
|
Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-09-09 22:49:53 +02:00
|
|
|
if (profile.Guid() == defaultProfileGuid)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
// Contrast the default profile with others in font weight.
|
|
|
|
profileMenuItem.FontWeight(FontWeights::Bold());
|
|
|
|
}
|
|
|
|
|
2020-10-13 02:14:02 +02:00
|
|
|
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 textBlock = WUX::Controls::TextBlock{};
|
|
|
|
textBlock.Inlines().Append(newTabRun);
|
|
|
|
textBlock.Inlines().Append(WUX::Documents::LineBreak{});
|
|
|
|
textBlock.Inlines().Append(newPaneRun);
|
|
|
|
|
|
|
|
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() })
|
|
|
|
{
|
2020-10-06 18:56:59 +02:00
|
|
|
NewTerminalArgs newTerminalArgs{ profileIndex };
|
2020-06-01 22:26:21 +02:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Check for DebugTap
|
2020-09-09 22:49:53 +02:00
|
|
|
bool debugTap = page->_settings.GlobalSettings().DebugFeaturesEnabled() &&
|
2020-06-01 22:26:21 +02:00
|
|
|
WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
|
|
|
|
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
|
|
|
|
|
|
|
|
if (altPressed && !debugTap)
|
|
|
|
{
|
2020-10-06 18:56:59 +02:00
|
|
|
page->_SplitPane(SplitState::Automatic,
|
|
|
|
SplitType::Manual,
|
Add `size` param to `splitPane` action, `split-pane` subcommand (#8543)
## Summary of the Pull Request
Adds a `size` parameter to `splitPane`. This takes a `float`, and specifies the portion of the parent pane that should be used to create the new one.
This also adds the param to the `split-pane` subcommand.
### Examples
| commandline | result |
| -- | -- |
| `wt ; sp -s .25` | ![image](https://user-images.githubusercontent.com/18356694/101784317-fb595680-3ac0-11eb-8248-782dc61957cf.png) |
| `wt ; sp -s .8` | ![image](https://user-images.githubusercontent.com/18356694/101784442-20e66000-3ac1-11eb-8f9b-fb45a73c9334.png) |
| `wt ; sp -s .8 ; sp -H -s .3` | ![image](https://user-images.githubusercontent.com/18356694/101784552-470c0000-3ac1-11eb-9deb-df37aaa36f01.png) |
## PR Checklist
* [x] Closes #6298
* [x] I work here
* [x] Tests added/passed
* [x] Docs PR: MicrosoftDocs/terminal#208
## Detailed Description of the Pull Request / Additional comments
I went with `size`, `--size,-s` rather than `percent`, because the arg is the (0,1) version of the size, not the (0%,100%) version.
## Validation Steps Performed
Added actions, played with the commandline, ran tests
2020-12-18 04:51:53 +01:00
|
|
|
0.5f,
|
2020-10-06 18:56:59 +02:00
|
|
|
newTerminalArgs);
|
2020-06-01 22:26:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-06 18:56:59 +02:00
|
|
|
page->_OpenNewTab(newTerminalArgs);
|
2020-06-01 22:26:21 +02:00
|
|
|
}
|
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
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
});
|
|
|
|
newTabFlyout.Items().Append(profileMenuItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
// add menu separator
|
2019-10-15 07:41:43 +02:00
|
|
|
auto separatorItem = WUX::Controls::MenuFlyoutSeparator{};
|
2019-09-04 23:34:06 +02:00
|
|
|
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();
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2019-12-09 20:07:08 +01:00
|
|
|
if (!isUwp)
|
|
|
|
{
|
|
|
|
// Create the settings button.
|
|
|
|
auto settingsItem = WUX::Controls::MenuFlyoutItem{};
|
|
|
|
settingsItem.Text(RS_(L"SettingsMenuItem"));
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2019-12-09 20:07:08 +01:00
|
|
|
WUX::Controls::SymbolIcon ico{};
|
|
|
|
ico.Symbol(WUX::Controls::Symbol::Setting);
|
|
|
|
settingsItem.Icon(ico);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2019-12-09 20:07:08 +01:00
|
|
|
settingsItem.Click({ this, &TerminalPage::_SettingsButtonOnClick });
|
|
|
|
newTabFlyout.Items().Append(settingsItem);
|
|
|
|
|
2021-01-04 23:14:51 +01:00
|
|
|
Microsoft::Terminal::Settings::Model::OpenSettingsArgs args{ SettingsTarget::SettingsFile };
|
|
|
|
Microsoft::Terminal::Settings::Model::ActionAndArgs settingsAction{ ShortcutAction::OpenSettings, args };
|
|
|
|
const auto settingsKeyChord{ keyBindings.GetKeyBindingForActionWithArgs(settingsAction) };
|
2019-12-09 20:07:08 +01:00
|
|
|
if (settingsKeyChord)
|
|
|
|
{
|
|
|
|
_SetAcceleratorForMenuItem(settingsItem, settingsKeyChord);
|
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2019-12-09 20:07:08 +01:00
|
|
|
// Create the feedback button.
|
|
|
|
auto feedbackFlyout = WUX::Controls::MenuFlyoutItem{};
|
|
|
|
feedbackFlyout.Text(RS_(L"FeedbackMenuItem"));
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2019-12-09 20:07:08 +01:00
|
|
|
WUX::Controls::FontIcon feedbackIcon{};
|
|
|
|
feedbackIcon.Glyph(L"\xE939");
|
|
|
|
feedbackIcon.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
|
|
|
|
feedbackFlyout.Icon(feedbackIcon);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2019-12-09 20:07:08 +01:00
|
|
|
feedbackFlyout.Click({ this, &TerminalPage::_FeedbackButtonOnClick });
|
|
|
|
newTabFlyout.Items().Append(feedbackFlyout);
|
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
// Create the about button.
|
2019-10-15 07:41:43 +02:00
|
|
|
auto aboutFlyout = WUX::Controls::MenuFlyoutItem{};
|
2019-11-01 23:47:05 +01:00
|
|
|
aboutFlyout.Text(RS_(L"AboutMenuItem"));
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2019-10-15 07:41:43 +02:00
|
|
|
WUX::Controls::SymbolIcon aboutIcon{};
|
|
|
|
aboutIcon.Symbol(WUX::Controls::Symbol::Help);
|
|
|
|
aboutFlyout.Icon(aboutIcon);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
aboutFlyout.Click({ this, &TerminalPage::_AboutButtonOnClick });
|
|
|
|
newTabFlyout.Items().Append(aboutFlyout);
|
|
|
|
}
|
|
|
|
|
2020-12-09 23:01:08 +01:00
|
|
|
// 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&&) {
|
|
|
|
if (auto index{ _GetFocusedTabIndex() })
|
|
|
|
{
|
|
|
|
_tabs.GetAt(*index).Focus(FocusState::Programmatic);
|
|
|
|
_UpdateMRUTab(index.value());
|
|
|
|
}
|
|
|
|
});
|
2019-09-04 23:34:06 +02:00
|
|
|
_newTabButton.Flyout(newTabFlyout);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function Description:
|
|
|
|
// Called when the openNewTabDropdown keybinding is used.
|
|
|
|
// Adds the flyout show option to left-align the dropdown with the split button.
|
|
|
|
// Shows the dropdown flyout.
|
|
|
|
void TerminalPage::_OpenNewTabDropdown()
|
|
|
|
{
|
2019-10-15 07:41:43 +02:00
|
|
|
WUX::Controls::Primitives::FlyoutShowOptions options{};
|
|
|
|
options.Placement(WUX::Controls::Primitives::FlyoutPlacementMode::BottomEdgeAlignedLeft);
|
2019-09-04 23:34:06 +02:00
|
|
|
_newTabButton.Flyout().ShowAt(_newTabButton, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Open a new tab. This will create the TerminalControl hosting the
|
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
|
|
|
// terminal, and add a new Tab to our list of tabs. The method can
|
|
|
|
// optionally be provided a NewTerminalArgs, which will be used to create
|
|
|
|
// a tab using the values in that object.
|
2019-09-04 23:34:06 +02:00
|
|
|
// Arguments:
|
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
|
2020-09-14 22:38:56 +02:00
|
|
|
// configurations. See TerminalSettings::BuildSettings for more details.
|
2020-10-06 18:56:59 +02:00
|
|
|
void TerminalPage::_OpenNewTab(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
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-09-14 22:38:56 +02:00
|
|
|
auto [profileGuid, settings] = TerminalSettings::BuildSettings(_settings, newTerminalArgs, *_bindings);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
_CreateNewTabFromSettings(profileGuid, settings);
|
|
|
|
|
2020-02-04 22:51:11 +01:00
|
|
|
const uint32_t tabCount = _tabs.Size();
|
2019-12-11 03:04:33 +01:00
|
|
|
const bool usedManualProfile = (newTerminalArgs != nullptr) &&
|
|
|
|
(newTerminalArgs.ProfileIndex() != nullptr ||
|
|
|
|
newTerminalArgs.Profile().empty());
|
2020-07-07 19:01:42 +02:00
|
|
|
|
|
|
|
// Lookup the name of the color scheme used by this profile.
|
2020-09-09 22:49:53 +02:00
|
|
|
const auto scheme = _settings.GetColorSchemeForProfile(profileGuid);
|
2020-07-07 19:01:42 +02:00
|
|
|
// If they explicitly specified `null` as the scheme (indicating _no_ scheme), log
|
|
|
|
// that as the empty string.
|
2020-08-15 02:54:35 +02:00
|
|
|
const auto schemeName = scheme ? scheme.Name() : L"\0";
|
2020-07-07 19:01:42 +02:00
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
TraceLoggingWrite(
|
|
|
|
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
|
|
|
|
"TabInformation",
|
|
|
|
TraceLoggingDescription("Event emitted upon new tab creation in TerminalApp"),
|
2020-02-12 21:02:48 +01:00
|
|
|
TraceLoggingUInt32(1u, "EventVer", "Version of this event"),
|
2020-02-10 21:40:01 +01:00
|
|
|
TraceLoggingUInt32(tabCount, "TabCount", "Count of tabs currently opened in 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
|
|
|
TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
|
2019-09-04 23:34:06 +02:00
|
|
|
TraceLoggingGuid(profileGuid, "ProfileGuid", "The GUID of the profile spawned in the new tab"),
|
2020-02-12 21:02:48 +01:00
|
|
|
TraceLoggingBool(settings.UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
|
|
|
|
TraceLoggingFloat64(settings.TintOpacity(), "TintOpacity", "Opacity preference from the settings"),
|
|
|
|
TraceLoggingWideString(settings.FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
|
2020-07-07 19:01:42 +02:00
|
|
|
TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
|
2019-09-04 23:34:06 +02:00
|
|
|
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
|
|
|
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
|
|
|
}
|
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();
|
2019-09-04 23:34:06 +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());
|
|
|
|
|
|
|
|
page->_RemoveTabViewItem(tabViewItem);
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Creates a new tab with the given settings. If the tab bar is not being
|
|
|
|
// currently displayed, it will be shown.
|
|
|
|
// Arguments:
|
|
|
|
// - settings: the TerminalSettings object to use to create the TerminalControl with.
|
2020-08-04 00:54:22 +02:00
|
|
|
void TerminalPage::_CreateNewTabFromSettings(GUID profileGuid, TerminalApp::TerminalSettings settings)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
// Initialize the new tab
|
|
|
|
|
|
|
|
// Create a connection based on the values in our settings object.
|
2020-03-26 23:33:47 +01:00
|
|
|
auto connection = _CreateConnectionFromSettings(profileGuid, settings);
|
|
|
|
|
|
|
|
TerminalConnection::ITerminalConnection debugConnection{ nullptr };
|
2020-09-09 22:49:53 +02:00
|
|
|
if (_settings.GlobalSettings().DebugFeaturesEnabled())
|
2020-03-26 23:33:47 +01:00
|
|
|
{
|
|
|
|
const CoreWindow window = CoreWindow::GetForCurrentThread();
|
|
|
|
const auto rAltState = window.GetKeyState(VirtualKey::RightMenu);
|
|
|
|
const auto lAltState = window.GetKeyState(VirtualKey::LeftMenu);
|
|
|
|
const bool bothAltsPressed = WI_IsFlagSet(lAltState, CoreVirtualKeyStates::Down) &&
|
|
|
|
WI_IsFlagSet(rAltState, CoreVirtualKeyStates::Down);
|
|
|
|
if (bothAltsPressed)
|
|
|
|
{
|
|
|
|
std::tie(connection, debugConnection) = OpenDebugTapConnection(connection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
TermControl term{ settings, connection };
|
|
|
|
|
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 newTabImpl = winrt::make_self<TerminalTab>(profileGuid, term);
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Add the new tab to the list of our tabs.
|
2020-02-04 22:51:11 +01:00
|
|
|
_tabs.Append(*newTabImpl);
|
2020-12-10 01:36:28 +01:00
|
|
|
_mruTabs.Append(*newTabImpl);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-10-15 13:40:44 +02:00
|
|
|
newTabImpl->SetDispatch(*_actionDispatch);
|
2021-01-19 12:44:04 +01:00
|
|
|
newTabImpl->SetKeyMap(_settings.KeyMap());
|
2020-10-15 13:40:44 +02:00
|
|
|
|
2020-09-18 02:13:11 +02:00
|
|
|
// Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command.
|
2020-10-15 13:40:44 +02:00
|
|
|
_UpdateTabIndices();
|
2020-09-18 02:13:11 +02:00
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Hookup our event handlers to the new terminal
|
2020-02-04 22:51:11 +01:00
|
|
|
_RegisterTerminalEvents(term, *newTabImpl);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
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
|
|
|
// 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.
|
2020-02-04 22:51:11 +01:00
|
|
|
auto weakTab = make_weak(newTabImpl);
|
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
|
|
|
|
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
|
|
|
// When the tab's active pane changes, we'll want to lookup a new icon
|
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
|
|
|
// for it. The Title change will be propagated upwards through the tab's
|
|
|
|
// PropertyChanged event handler.
|
2020-02-04 22:51:11 +01:00
|
|
|
newTabImpl->ActivePaneChanged([weakTab, weakThis{ get_weak() }]() {
|
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() };
|
2020-02-04 22:51:11 +01:00
|
|
|
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)
|
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
|
|
|
{
|
|
|
|
// Possibly update the icon of the tab.
|
2020-02-04 22:51:11 +01:00
|
|
|
page->_UpdateTabIcon(*tab);
|
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
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-11-18 23:55:10 +01:00
|
|
|
// The RaiseVisualBell event has been bubbled up to here from the pane,
|
|
|
|
// the next part of the chain is bubbling up to app logic, which will
|
|
|
|
// forward it to app host.
|
|
|
|
newTabImpl->TabRaiseVisualBell([weakTab, weakThis{ get_weak() }]() {
|
|
|
|
auto page{ weakThis.get() };
|
|
|
|
auto tab{ weakTab.get() };
|
|
|
|
|
|
|
|
if (page && tab)
|
|
|
|
{
|
|
|
|
page->_raiseVisualBellHandlers(nullptr, nullptr);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
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 tabViewItem = newTabImpl->TabViewItem();
|
2019-10-15 07:41:43 +02:00
|
|
|
_tabView.TabItems().Append(tabViewItem);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
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
|
|
|
// Set this tab's icon to the icon from the user's profile
|
2020-09-09 22:49:53 +02:00
|
|
|
const auto profile = _settings.FindProfile(profileGuid);
|
2020-10-08 20:29:04 +02:00
|
|
|
if (profile != nullptr && !profile.Icon().empty())
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-10-08 20:29:04 +02:00
|
|
|
newTabImpl->UpdateIcon(profile.Icon());
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick });
|
|
|
|
|
|
|
|
// When the tab is closed, remove it from our list of tabs.
|
2020-02-04 22:51:11 +01:00
|
|
|
newTabImpl->Closed([tabViewItem, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*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
|
|
|
if (auto page{ weakThis.get() })
|
|
|
|
{
|
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
|
|
|
page->_RemoveOnCloseRoutine(tabViewItem, page);
|
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
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
});
|
|
|
|
|
2020-03-26 23:33:47 +01:00
|
|
|
if (debugConnection) // this will only be set if global debugging is on and tap is active
|
|
|
|
{
|
|
|
|
TermControl newControl{ settings, debugConnection };
|
|
|
|
_RegisterTerminalEvents(newControl, *newTabImpl);
|
|
|
|
// Split (auto) with the debug tap.
|
Add `size` param to `splitPane` action, `split-pane` subcommand (#8543)
## Summary of the Pull Request
Adds a `size` parameter to `splitPane`. This takes a `float`, and specifies the portion of the parent pane that should be used to create the new one.
This also adds the param to the `split-pane` subcommand.
### Examples
| commandline | result |
| -- | -- |
| `wt ; sp -s .25` | ![image](https://user-images.githubusercontent.com/18356694/101784317-fb595680-3ac0-11eb-8248-782dc61957cf.png) |
| `wt ; sp -s .8` | ![image](https://user-images.githubusercontent.com/18356694/101784442-20e66000-3ac1-11eb-8f9b-fb45a73c9334.png) |
| `wt ; sp -s .8 ; sp -H -s .3` | ![image](https://user-images.githubusercontent.com/18356694/101784552-470c0000-3ac1-11eb-9deb-df37aaa36f01.png) |
## PR Checklist
* [x] Closes #6298
* [x] I work here
* [x] Tests added/passed
* [x] Docs PR: MicrosoftDocs/terminal#208
## Detailed Description of the Pull Request / Additional comments
I went with `size`, `--size,-s` rather than `percent`, because the arg is the (0,1) version of the size, not the (0%,100%) version.
## Validation Steps Performed
Added actions, played with the commandline, ran tests
2020-12-18 04:51:53 +01:00
|
|
|
newTabImpl->SplitPane(SplitState::Automatic, 0.5f, profileGuid, newControl);
|
2020-03-26 23:33:47 +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
|
|
|
// This kicks off TabView::SelectionChanged, in response to which
|
|
|
|
// we'll attach the terminal's Xaml control to the Xaml root.
|
|
|
|
_tabView.SelectedItem(tabViewItem);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Creates a new connection based on the profile settings
|
|
|
|
// Arguments:
|
|
|
|
// - the profile GUID we want the settings from
|
|
|
|
// - the terminal settings
|
|
|
|
// Return value:
|
|
|
|
// - the desired connection
|
|
|
|
TerminalConnection::ITerminalConnection TerminalPage::_CreateConnectionFromSettings(GUID profileGuid,
|
2020-08-04 00:54:22 +02:00
|
|
|
TerminalApp::TerminalSettings settings)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-09-09 22:49:53 +02:00
|
|
|
const auto profile = _settings.FindProfile(profileGuid);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
TerminalConnection::ITerminalConnection connection{ nullptr };
|
|
|
|
|
2020-10-27 18:35:09 +01:00
|
|
|
winrt::guid connectionType = profile.ConnectionType();
|
2020-08-28 03:09:22 +02:00
|
|
|
winrt::guid sessionGuid{};
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-10-27 18:35:09 +01:00
|
|
|
if (connectionType == TerminalConnection::AzureConnection::ConnectionType() &&
|
2019-09-04 23:34:06 +02:00
|
|
|
TerminalConnection::AzureConnection::IsAzureConnectionAvailable())
|
|
|
|
{
|
2020-02-21 01:21:05 +01:00
|
|
|
// 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");
|
2020-04-17 19:15:20 +02:00
|
|
|
connection = TerminalConnection::ConptyConnection(azBridgePath.wstring(),
|
|
|
|
L".",
|
|
|
|
L"Azure",
|
|
|
|
nullptr,
|
|
|
|
settings.InitialRows(),
|
|
|
|
settings.InitialCols(),
|
|
|
|
winrt::guid());
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
2020-04-17 19:15:20 +02:00
|
|
|
std::wstring guidWString = Utils::GuidToString(profileGuid);
|
|
|
|
|
|
|
|
StringMap envMap{};
|
|
|
|
envMap.Insert(L"WT_PROFILE_ID", guidWString);
|
|
|
|
envMap.Insert(L"WSLENV", L"WT_PROFILE_ID");
|
|
|
|
|
|
|
|
auto conhostConn = TerminalConnection::ConptyConnection(
|
|
|
|
settings.Commandline(),
|
|
|
|
settings.StartingDirectory(),
|
|
|
|
settings.StartingTitle(),
|
|
|
|
envMap.GetView(),
|
|
|
|
settings.InitialRows(),
|
|
|
|
settings.InitialCols(),
|
|
|
|
winrt::guid());
|
|
|
|
|
2019-09-05 22:38:42 +02:00
|
|
|
sessionGuid = conhostConn.Guid();
|
|
|
|
connection = conhostConn;
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
TraceLoggingWrite(
|
|
|
|
g_hTerminalAppProvider,
|
|
|
|
"ConnectionCreated",
|
|
|
|
TraceLoggingDescription("Event emitted upon the creation of a connection"),
|
|
|
|
TraceLoggingGuid(connectionType, "ConnectionTypeGuid", "The type of the connection"),
|
2019-09-05 22:38:42 +02:00
|
|
|
TraceLoggingGuid(profileGuid, "ProfileGuid", "The profile's GUID"),
|
|
|
|
TraceLoggingGuid(sessionGuid, "SessionGuid", "The WT_SESSION's GUID"),
|
2019-09-04 23:34:06 +02:00
|
|
|
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();
|
|
|
|
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);
|
|
|
|
|
Add keybinding arg to openSettings (#6299)
## Summary of the Pull Request
Adds the `target` keybinding arg to `openSettings`. Possible values include: `defaultsFile`, `settingsFile`, and `allFiles`.
## References
#5915 - mini-spec
## PR Checklist
* [x] Closes #2557
* [x] Tests added/passed
## Detailed Description of the Pull Request / Additional comments
Implemented as discussed in the attached spec. A new enum will be added for the SettingsUI when it becomes available.
## Validation Steps Performed
Added the following to my settings.json:
```json
{ "command": "openSettings", "keys":... },
{ "command": { "action": "openSettings" }, "keys":... },
{ "command": { "action": "openSettings", "target": "settingsFile" }, "keys":... },
{ "command": { "action": "openSettings", "target": "defaultsFile" }, "keys":... },
{ "command": { "action": "openSettings", "target": "allFiles" }, "keys":... }
```
2020-06-12 23:19:18 +02:00
|
|
|
const auto target = altPressed ? SettingsTarget::DefaultsFile : SettingsTarget::SettingsFile;
|
|
|
|
_LaunchSettings(target);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Called when the feedback button is clicked. Launches github in your
|
|
|
|
// default browser, navigated to the "issues" page of the Terminal repo.
|
|
|
|
void TerminalPage::_FeedbackButtonOnClick(const IInspectable&,
|
|
|
|
const RoutedEventArgs&)
|
|
|
|
{
|
2019-11-01 23:47:05 +01:00
|
|
|
const auto feedbackUriValue = RS_(L"FeedbackUriValue");
|
2020-03-23 18:15:24 +01:00
|
|
|
winrt::Windows::Foundation::Uri feedbackUri{ feedbackUriValue };
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-03-23 18:15:24 +01:00
|
|
|
winrt::Windows::System::Launcher::LaunchUriAsync(feedbackUri);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
2020-12-18 18:09:30 +01:00
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
auto key = e.OriginalKey();
|
|
|
|
auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
|
|
|
|
auto const altDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down);
|
|
|
|
auto const shiftDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down);
|
|
|
|
|
|
|
|
winrt::Microsoft::Terminal::TerminalControl::KeyChord kc{ ctrlDown, altDown, shiftDown, static_cast<int32_t>(key) };
|
2021-01-08 00:09:16 +01:00
|
|
|
const auto actionAndArgs = _settings.KeyMap().TryLookup(kc);
|
2020-12-18 18:09:30 +01:00
|
|
|
if (actionAndArgs)
|
|
|
|
{
|
|
|
|
if (CommandPalette().Visibility() == Visibility::Visible && actionAndArgs.Action() != ShortcutAction::ToggleCommandPalette)
|
|
|
|
{
|
|
|
|
CommandPalette().Visibility(Visibility::Collapsed);
|
|
|
|
}
|
|
|
|
_actionDispatch->DoAction(actionAndArgs);
|
|
|
|
e.Handled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-25 23:52:12 +01:00
|
|
|
// Method Description:
|
|
|
|
// Handles preview key on the SUI tab, by handling close tab / next tab / previous tab
|
|
|
|
// This is a temporary solution - we need to fix all key-bindings work from SUI as long as they don't harm
|
|
|
|
// the SUI behavior
|
|
|
|
// Arguments:
|
|
|
|
// - e: the KeyRoutedEventArgs containing info about the keystroke.
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void TerminalPage::_SUIPreviewKeyDownHandler(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
|
|
|
{
|
|
|
|
auto key = e.OriginalKey();
|
|
|
|
auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
|
|
|
|
auto const altDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down);
|
|
|
|
auto const shiftDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down);
|
|
|
|
|
|
|
|
winrt::Microsoft::Terminal::TerminalControl::KeyChord kc{ ctrlDown, altDown, shiftDown, static_cast<int32_t>(key) };
|
|
|
|
const auto actionAndArgs = _settings.KeyMap().TryLookup(kc);
|
2021-01-26 20:14:28 +01:00
|
|
|
if (actionAndArgs && (actionAndArgs.Action() == ShortcutAction::CloseTab || actionAndArgs.Action() == ShortcutAction::NextTab || actionAndArgs.Action() == ShortcutAction::PrevTab || actionAndArgs.Action() == ShortcutAction::ClosePane))
|
2021-01-25 23:52:12 +01:00
|
|
|
{
|
|
|
|
_actionDispatch->DoAction(actionAndArgs);
|
|
|
|
e.Handled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Method Description:
|
2020-09-14 22:38:56 +02:00
|
|
|
// - Configure the AppKeyBindings to use our ShortcutActionDispatch and the updated KeyMapping
|
|
|
|
// as the object to handle dispatching ShortcutAction events.
|
2019-09-04 23:34:06 +02:00
|
|
|
// Arguments:
|
|
|
|
// - bindings: A AppKeyBindings object to wire up with our event handlers
|
2020-10-06 18:56:59 +02:00
|
|
|
void TerminalPage::_HookupKeyBindings(const KeyMapping& keymap) noexcept
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-09-14 22:38:56 +02:00
|
|
|
_bindings->SetDispatch(*_actionDispatch);
|
|
|
|
_bindings->SetKeyMapping(keymap);
|
2019-11-27 22:51:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2019-09-04 23:34:06 +02:00
|
|
|
// They should all be hooked up here, regardless of whether or not
|
|
|
|
// there's an actual keychord for them.
|
2019-12-11 03:04:33 +01:00
|
|
|
_actionDispatch->OpenNewTabDropdown({ this, &TerminalPage::_HandleOpenNewTabDropdown });
|
|
|
|
_actionDispatch->DuplicateTab({ this, &TerminalPage::_HandleDuplicateTab });
|
|
|
|
_actionDispatch->CloseTab({ this, &TerminalPage::_HandleCloseTab });
|
|
|
|
_actionDispatch->ClosePane({ this, &TerminalPage::_HandleClosePane });
|
|
|
|
_actionDispatch->CloseWindow({ this, &TerminalPage::_HandleCloseWindow });
|
|
|
|
_actionDispatch->ScrollUp({ this, &TerminalPage::_HandleScrollUp });
|
|
|
|
_actionDispatch->ScrollDown({ this, &TerminalPage::_HandleScrollDown });
|
|
|
|
_actionDispatch->NextTab({ this, &TerminalPage::_HandleNextTab });
|
|
|
|
_actionDispatch->PrevTab({ this, &TerminalPage::_HandlePrevTab });
|
2020-08-12 15:46:53 +02:00
|
|
|
_actionDispatch->SendInput({ this, &TerminalPage::_HandleSendInput });
|
2019-12-11 03:04:33 +01:00
|
|
|
_actionDispatch->SplitPane({ this, &TerminalPage::_HandleSplitPane });
|
2020-08-08 01:11:44 +02:00
|
|
|
_actionDispatch->TogglePaneZoom({ this, &TerminalPage::_HandleTogglePaneZoom });
|
2019-12-11 03:04:33 +01:00
|
|
|
_actionDispatch->ScrollUpPage({ this, &TerminalPage::_HandleScrollUpPage });
|
|
|
|
_actionDispatch->ScrollDownPage({ this, &TerminalPage::_HandleScrollDownPage });
|
2020-12-08 18:28:41 +01:00
|
|
|
_actionDispatch->ScrollToTop({ this, &TerminalPage::_HandleScrollToTop });
|
|
|
|
_actionDispatch->ScrollToBottom({ this, &TerminalPage::_HandleScrollToBottom });
|
2019-12-11 03:04:33 +01:00
|
|
|
_actionDispatch->OpenSettings({ this, &TerminalPage::_HandleOpenSettings });
|
|
|
|
_actionDispatch->PasteText({ this, &TerminalPage::_HandlePasteText });
|
|
|
|
_actionDispatch->NewTab({ this, &TerminalPage::_HandleNewTab });
|
|
|
|
_actionDispatch->SwitchToTab({ this, &TerminalPage::_HandleSwitchToTab });
|
|
|
|
_actionDispatch->ResizePane({ this, &TerminalPage::_HandleResizePane });
|
|
|
|
_actionDispatch->MoveFocus({ this, &TerminalPage::_HandleMoveFocus });
|
|
|
|
_actionDispatch->CopyText({ this, &TerminalPage::_HandleCopyText });
|
|
|
|
_actionDispatch->AdjustFontSize({ this, &TerminalPage::_HandleAdjustFontSize });
|
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
|
|
|
_actionDispatch->Find({ this, &TerminalPage::_HandleFind });
|
2019-12-11 03:04:33 +01:00
|
|
|
_actionDispatch->ResetFontSize({ this, &TerminalPage::_HandleResetFontSize });
|
Implement user-specified pixel shaders, redux (#8565)
Co-authored-by: mrange <marten_range@hotmail.com>
I loved the pixel shaders in #7058, but that PR needed a bit of polish
to be ready for ingestion. This PR is almost _exactly_ that PR, with
some small changes.
* It adds a new pre-profile setting `"experimental.pixelShaderPath"`,
which lets the user set a pixel shader to use with the Terminal.
- CHANGED FROM #7058: It does _not_ add any built-in shaders.
- CHANGED FROM #7058: it will _override_
`experimental.retroTerminalEffect`
* It adds a bunch of sample shaders in `samples/shaders`. Included:
- A NOP shader as a base to build from.
- An "invert" shader that inverts the colors, as a simple example
- An "grayscale" shader that converts all colors to grayscale, as a
simple example
- An "raster bars" shader that draws some colored bars on the screen
with a drop shadow, as a more involved example
- The original retro terminal effects, as a more involved example
- It also includes a broken shader, as an example of what heppens
when the shader fails to compile
- CHANGED FROM #7058: It does _not_ add the "retroII" shader we were
all worried about.
* When a shader fails to be found or fails to compile, we'll display an
error dialog to the user with a relevant error message.
- CHANGED FROM #7058: Originally, #7058 would display "error bars"
on the screen. I've removed that, and had the Terminal disable the
shader entirely then.
* Renames the `toggleRetroEffect` action to `toggleShaderEffect`.
(`toggleRetroEffect` is now an alias to `toggleShaderEffect`). This
action will turn the shader OR the retro effects on/off.
`toggleShaderEffect` works the way you'd expect it to, but the mental
math on _how_ is a little weird. The logic is basically:
```
useShader = shaderEffectsEnabled ?
(pixelShaderProvided ?
pixelShader :
(retroEffectEnabled ?
retroEffect : null
)
) :
null
```
and `toggleShaderEffect` toggles `shaderEffectsEnabled`.
* If you've got both a shader and retro enabled, `toggleShaderEffect`
will toggle between the shader on/off.
* If you've got a shader and retro disabled, `toggleShaderEffect` will
toggle between the shader on/off.
References #6191
References #7058
Closes #7013
Closes #3930 "Add setting to retro terminal shader to control blur
radius, color"
Closes #3929 "Add setting to retro terminal shader to enable drawing
scanlines"
- At this point, just roll your own version of the shader.
2020-12-15 21:40:22 +01:00
|
|
|
_actionDispatch->ToggleShaderEffects({ this, &TerminalPage::_HandleToggleShaderEffects });
|
2020-07-13 19:40:20 +02:00
|
|
|
_actionDispatch->ToggleFocusMode({ this, &TerminalPage::_HandleToggleFocusMode });
|
2019-12-11 03:04:33 +01:00
|
|
|
_actionDispatch->ToggleFullscreen({ this, &TerminalPage::_HandleToggleFullscreen });
|
2020-07-14 23:02:18 +02:00
|
|
|
_actionDispatch->ToggleAlwaysOnTop({ this, &TerminalPage::_HandleToggleAlwaysOnTop });
|
2020-06-26 22:38:02 +02:00
|
|
|
_actionDispatch->ToggleCommandPalette({ this, &TerminalPage::_HandleToggleCommandPalette });
|
2020-08-10 18:21:56 +02:00
|
|
|
_actionDispatch->SetColorScheme({ this, &TerminalPage::_HandleSetColorScheme });
|
Add `setTabColor` and `openTabColorPicker` actions (#6567)
## Summary of the Pull Request
Adds a pair of `ShortcutAction`s for setting the tab color.
* `setTabColor`: This changes the color of the current tab to the provided color, or can be used to clear the color.
* `openTabColorPicker`: This keybinding immediately activates the tab color picker for the currently focused tab.
## References
## PR Checklist
* [x] scratches my own itch
* [x] I work here
* [x] Tests added/passed
* [x] https://github.com/MicrosoftDocs/terminal/pull/69
## Detailed Description of the Pull Request / Additional comments
## Validation Steps Performed
* hey look there are tests
* Tested with the following:
```json
// { "command": "setTabColor", "keys": [ "alt+c" ] },
{ "keys": "ctrl+alt+c", "command": { "action": "setTabColor", "color": "#123456" } },
{ "keys": "alt+shift+c", "command": { "action": "setTabColor", "color": null} },
{ "keys": "alt+c", "command": "openTabColorPicker" },
```
2020-06-25 15:06:21 +02:00
|
|
|
_actionDispatch->SetTabColor({ this, &TerminalPage::_HandleSetTabColor });
|
|
|
|
_actionDispatch->OpenTabColorPicker({ this, &TerminalPage::_HandleOpenTabColorPicker });
|
2020-06-24 22:07:41 +02:00
|
|
|
_actionDispatch->RenameTab({ this, &TerminalPage::_HandleRenameTab });
|
2020-10-28 20:36:30 +01:00
|
|
|
_actionDispatch->OpenTabRenamer({ this, &TerminalPage::_HandleOpenTabRenamer });
|
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
|
|
|
_actionDispatch->ExecuteCommandline({ this, &TerminalPage::_HandleExecuteCommandline });
|
2020-08-06 23:47:50 +02:00
|
|
|
_actionDispatch->CloseOtherTabs({ this, &TerminalPage::_HandleCloseOtherTabs });
|
|
|
|
_actionDispatch->CloseTabsAfter({ this, &TerminalPage::_HandleCloseTabsAfter });
|
2020-08-21 17:39:40 +02:00
|
|
|
_actionDispatch->TabSearch({ this, &TerminalPage::_HandleOpenTabSearch });
|
2020-11-25 23:09:27 +01:00
|
|
|
_actionDispatch->MoveTab({ this, &TerminalPage::_HandleMoveTab });
|
2020-12-05 00:54:59 +01:00
|
|
|
_actionDispatch->BreakIntoDebugger({ this, &TerminalPage::_HandleBreakIntoDebugger });
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2019-09-04 23:34:06 +02:00
|
|
|
// 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)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
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();
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-09-09 22:49:53 +02:00
|
|
|
if (_settings.GlobalSettings().ShowTitleInTitlebar() &&
|
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.FocusState() != FocusState::Unfocused)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
_titleChangeHandlers(*this, newTabTitle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Get the icon of the currently focused terminal control, and set its
|
|
|
|
// tab's icon to that icon.
|
|
|
|
// 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::_UpdateTabIcon(TerminalTab& tab)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-02-04 22:51:11 +01:00
|
|
|
const auto lastFocusedProfileOpt = tab.GetFocusedProfile();
|
2019-09-04 23:34:06 +02:00
|
|
|
if (lastFocusedProfileOpt.has_value())
|
|
|
|
{
|
|
|
|
const auto lastFocusedProfile = lastFocusedProfileOpt.value();
|
2020-09-09 22:49:53 +02:00
|
|
|
const auto matchingProfile = _settings.FindProfile(lastFocusedProfile);
|
2019-09-04 23:34:06 +02:00
|
|
|
if (matchingProfile)
|
|
|
|
{
|
2020-10-08 20:29:04 +02:00
|
|
|
tab.UpdateIcon(matchingProfile.Icon());
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-02-04 22:51:11 +01:00
|
|
|
tab.UpdateIcon({});
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-10 01:16:54 +01:00
|
|
|
// Method Description:
|
|
|
|
// - Handle changes to the tab width set by the user
|
|
|
|
void TerminalPage::_UpdateTabWidthMode()
|
|
|
|
{
|
2020-09-09 22:49:53 +02:00
|
|
|
_tabView.TabWidthMode(_settings.GlobalSettings().TabWidthMode());
|
2020-01-10 01:16:54 +01:00
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Handle changes in tab layout.
|
|
|
|
void TerminalPage::_UpdateTabView()
|
|
|
|
{
|
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
|
|
|
// Never show the tab row when we're fullscreen. Otherwise:
|
2019-09-04 23:34:06 +02:00
|
|
|
// Show tabs when there's more than 1, or the user has chosen to always
|
|
|
|
// show the tab bar.
|
2020-07-13 19:40:20 +02:00
|
|
|
const bool isVisible = (!_isFullscreen && !_isInFocusMode) &&
|
2020-09-09 22:49:53 +02:00
|
|
|
(_settings.GlobalSettings().ShowTabsInTitlebar() ||
|
2020-02-04 22:51:11 +01:00
|
|
|
(_tabs.Size() > 1) ||
|
2020-09-09 22:49:53 +02:00
|
|
|
_settings.GlobalSettings().AlwaysShowTabs());
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
// collapse/show the tabs themselves
|
|
|
|
_tabView.Visibility(isVisible ? Visibility::Visible : Visibility::Collapsed);
|
|
|
|
|
|
|
|
// collapse/show the row that the tabs are in.
|
|
|
|
// NaN is the special value XAML uses for "Auto" sizing.
|
|
|
|
_tabRow.Height(isVisible ? NAN : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Duplicates the current focused tab
|
|
|
|
void TerminalPage::_DuplicateTabViewItem()
|
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
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
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
try
|
2020-02-04 22:51:11 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +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.
|
|
|
|
|
|
|
|
const auto& profileGuid = terminalTab->GetFocusedProfile();
|
|
|
|
if (profileGuid.has_value())
|
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
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
const auto settings{ winrt::make<TerminalSettings>(_settings, profileGuid.value(), *_bindings) };
|
2021-01-11 19:01:38 +01:00
|
|
|
const auto workingDirectory = terminalTab->GetActiveTerminalControl().WorkingDirectory();
|
|
|
|
const auto validWorkingDirectory = !workingDirectory.empty();
|
|
|
|
if (validWorkingDirectory)
|
|
|
|
{
|
|
|
|
settings.StartingDirectory(workingDirectory);
|
|
|
|
}
|
|
|
|
|
2021-01-04 20:32:53 +01:00
|
|
|
_CreateNewTabFromSettings(profileGuid.value(), settings);
|
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
|
|
|
}
|
2020-02-04 22:51:11 +01:00
|
|
|
}
|
2021-01-04 20:32:53 +01:00
|
|
|
CATCH_LOG();
|
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
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
2019-09-17 07:43:27 +02:00
|
|
|
// - Look for the index of the input tabView in the tabs vector,
|
|
|
|
// and call _RemoveTabViewItemByIndex
|
2019-09-04 23:34:06 +02:00
|
|
|
// Arguments:
|
|
|
|
// - tabViewItem: the TabViewItem in the TabView that is being removed.
|
2019-10-15 07:41:43 +02:00
|
|
|
void TerminalPage::_RemoveTabViewItem(const MUX::Controls::TabViewItem& tabViewItem)
|
2019-09-17 07:43:27 +02:00
|
|
|
{
|
|
|
|
uint32_t tabIndexFromControl = 0;
|
2020-05-05 18:16:09 +02:00
|
|
|
if (_tabView.TabItems().IndexOf(tabViewItem, tabIndexFromControl))
|
|
|
|
{
|
|
|
|
// If IndexOf returns true, we've actually got an index
|
|
|
|
_RemoveTabViewItemByIndex(tabIndexFromControl);
|
|
|
|
}
|
2019-09-17 07:43:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Removes the tab (both TerminalControl and XAML)
|
|
|
|
// Arguments:
|
|
|
|
// - tabIndex: the index of the tab to be removed
|
|
|
|
void TerminalPage::_RemoveTabViewItemByIndex(uint32_t tabIndex)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-12-18 11:11:25 +01:00
|
|
|
// We use _removing flag to suppress _OnTabSelectionChanged events
|
|
|
|
// that might get triggered while removing
|
|
|
|
_removing = true;
|
|
|
|
auto unsetRemoving = wil::scope_exit([&]() noexcept { _removing = false; });
|
|
|
|
|
|
|
|
const auto focusedTabIndex{ _GetFocusedTabIndex() };
|
|
|
|
|
2020-01-23 23:12:20 +01:00
|
|
|
// Removing the tab from the collection should destroy its control and disconnect its connection,
|
|
|
|
// but it doesn't always do so. The UI tree may still be holding the control and preventing its destruction.
|
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 tab{ _tabs.GetAt(tabIndex) };
|
|
|
|
tab.Shutdown();
|
2020-01-23 23:12:20 +01:00
|
|
|
|
2020-10-21 21:37:28 +02:00
|
|
|
uint32_t mruIndex;
|
2020-12-10 01:36:28 +01:00
|
|
|
if (_mruTabs.IndexOf(_tabs.GetAt(tabIndex), mruIndex))
|
2020-10-21 21:37:28 +02:00
|
|
|
{
|
2020-12-10 01:36:28 +01:00
|
|
|
_mruTabs.RemoveAt(mruIndex);
|
2020-10-21 21:37:28 +02:00
|
|
|
}
|
|
|
|
|
2020-02-04 22:51:11 +01:00
|
|
|
_tabs.RemoveAt(tabIndex);
|
2020-01-23 23:12:20 +01:00
|
|
|
_tabView.TabItems().RemoveAt(tabIndex);
|
2020-09-18 02:13:11 +02:00
|
|
|
_UpdateTabIndices();
|
2020-01-23 23:12:20 +01:00
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// To close the window here, we need to close the hosting window.
|
2020-02-04 22:51:11 +01:00
|
|
|
if (_tabs.Size() == 0)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
_lastTabClosedHandlers(*this, nullptr);
|
|
|
|
}
|
2020-12-18 11:11:25 +01:00
|
|
|
else if (focusedTabIndex.has_value() && focusedTabIndex.value() == gsl::narrow_cast<uint32_t>(tabIndex))
|
|
|
|
{
|
|
|
|
// Manually select the new tab to get focus, rather than relying on TabView since:
|
|
|
|
// 1. We want to customize this behavior (e.g., use MRU logic)
|
|
|
|
// 2. In fullscreen (GH#5799) and focus (GH#7916) modes the _OnTabItemsChanged is not fired
|
|
|
|
// 3. When rearranging tabs (GH#7916) _OnTabItemsChanged is suppressed
|
|
|
|
const auto tabSwitchMode = _settings.GlobalSettings().TabSwitcherMode();
|
|
|
|
|
|
|
|
if (tabSwitchMode == TabSwitcherMode::MostRecentlyUsed)
|
|
|
|
{
|
|
|
|
const auto newSelectedTab = _mruTabs.GetAt(0);
|
|
|
|
|
|
|
|
uint32_t newSelectedIndex;
|
|
|
|
if (_tabs.IndexOf(newSelectedTab, newSelectedIndex))
|
|
|
|
{
|
|
|
|
_UpdatedSelectedTab(newSelectedIndex);
|
|
|
|
_tabView.SelectedItem(newSelectedTab.TabViewItem());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// We can't use
|
|
|
|
// auto selectedIndex = _tabView.SelectedIndex();
|
|
|
|
// Because this will always return -1 in this scenario unfortunately.
|
|
|
|
//
|
|
|
|
// So, what we're going to try to do is move the focus to the tab
|
|
|
|
// to the left, within the bounds of how many tabs we have.
|
|
|
|
//
|
|
|
|
// EX: we have 4 tabs: [A, B, C, D]. If we close:
|
|
|
|
// * A (tabIndex=0): We'll want to focus tab B (now in index 0)
|
|
|
|
// * B (tabIndex=1): We'll want to focus tab A (now in index 0)
|
|
|
|
// * C (tabIndex=2): We'll want to focus tab B (now in index 1)
|
|
|
|
// * D (tabIndex=3): We'll want to focus tab C (now in index 2)
|
|
|
|
const auto newSelectedIndex = std::clamp<int32_t>(tabIndex - 1, 0, _tabs.Size());
|
|
|
|
// _UpdatedSelectedTab will do the work of setting up the new tab as
|
|
|
|
// the focused one, and unfocusing all the others.
|
|
|
|
_UpdatedSelectedTab(newSelectedIndex);
|
|
|
|
|
|
|
|
// Also, we need to _manually_ set the SelectedItem of the tabView
|
|
|
|
// here. If we don't, then the TabView will technically not have a
|
|
|
|
// selected item at all, which can make things like ClosePane not
|
|
|
|
// work correctly.
|
|
|
|
auto newSelectedTab{ _tabs.GetAt(newSelectedIndex) };
|
|
|
|
_tabView.SelectedItem(newSelectedTab.TabViewItem());
|
|
|
|
}
|
Manually select a new tab when we're in fullscreen mode (#5809)
If we're fullscreen, the TabView isn't `Visible`. If it's not `Visible`,
it's _not_ going to raise a `SelectionChanged` event, which is what we
usually use to focus another tab. Instead, we'll have to do it manually
here.
So, what we're going to try to do is move the focus to the tab to the
left, within the bounds of how many tabs we have.
EX: we have 4 tabs: [A, B, C, D]. If we close:
* A (`tabIndex=0`): We'll want to focus tab B (now in index 0)
* B (`tabIndex=1`): We'll want to focus tab A (now in index 0)
* C (`tabIndex=2`): We'll want to focus tab B (now in index 1)
* D (`tabIndex=3`): We'll want to focus tab C (now in index 2)
`_UpdatedSelectedTab` will do the work of setting up the new tab as the
focused one, and unfocusing all the others.
Also, we need to _manually_ set the SelectedItem of the tabView here. If
we don't, then the TabView will technically not have a selected item at
all, which can make things like ClosePane not work correctly.
## PR Checklist
* [x] Closes #5799
* [x] I work here
* [ ] Tests added/passed
* [n/a] Requires documentation to be updated
## Validation Steps Performed
Played with it a bunch
2020-05-08 20:53:34 +02:00
|
|
|
}
|
2020-05-14 03:47:32 +02:00
|
|
|
|
|
|
|
// GH#5559 - If we were in the middle of a drag/drop, end it by clearing
|
|
|
|
// out our state.
|
|
|
|
if (_rearranging)
|
|
|
|
{
|
|
|
|
_rearranging = false;
|
|
|
|
_rearrangeFrom = std::nullopt;
|
|
|
|
_rearrangeTo = std::nullopt;
|
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2019-11-25 21:23:08 +01:00
|
|
|
// * the TitleChanged event, for changing the text of the tab
|
2019-09-04 23:34:06 +02:00
|
|
|
// Arguments:
|
|
|
|
// - term: The newly created TermControl to connect the events for
|
|
|
|
// - hostingTab: The Tab that's hosting this TermControl instance
|
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::_RegisterTerminalEvents(TermControl term, TerminalTab& hostingTab)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-11-11 03:24:06 +01:00
|
|
|
term.RaiseNotice({ this, &TerminalPage::_ControlNoticeRaisedHandler });
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// 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 });
|
2019-11-25 21:23:08 +01:00
|
|
|
|
2020-09-03 19:52:39 +02:00
|
|
|
term.OpenHyperlink({ this, &TerminalPage::_OpenHyperlinkHandler });
|
|
|
|
|
2020-11-18 23:24:11 +01:00
|
|
|
// Add an event handler for when the terminal wants to set a progress indicator on the taskbar
|
|
|
|
term.SetTaskbarProgress({ this, &TerminalPage::_SetTaskbarProgressHandler });
|
|
|
|
|
2021-01-21 02:17:59 +01:00
|
|
|
term.HidePointerCursor({ this, &TerminalPage::_HidePointerCursorHandler });
|
|
|
|
term.RestorePointerCursor({ this, &TerminalPage::_RestorePointerCursorHandler });
|
|
|
|
|
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
|
|
|
// Bind Tab events to the TermControl and the Tab's Pane
|
2020-05-04 22:57:12 +02:00
|
|
|
hostingTab.Initialize(term);
|
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
|
|
|
|
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() };
|
2020-02-04 22:51:11 +01:00
|
|
|
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)
|
2019-11-25 21:23:08 +01:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
}
|
2019-11-25 21:23:08 +01:00
|
|
|
}
|
|
|
|
});
|
2020-05-04 22:57:12 +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) {
|
2020-05-04 22:57:12 +02:00
|
|
|
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))
|
2020-05-04 22:57:12 +02:00
|
|
|
{
|
|
|
|
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]() {
|
2020-05-04 22:57:12 +02:00
|
|
|
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))
|
2020-05-04 22:57:12 +02:00
|
|
|
{
|
|
|
|
page->_ClearNonClientAreaColors();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-05-05 22:33:07 +02:00
|
|
|
// 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).
|
2020-05-04 22:57:12 +02:00
|
|
|
// remove any colors left by other colored tabs
|
2020-05-05 22:33:07 +02:00
|
|
|
// _ClearNewTabButtonColor();
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Sets focus to the tab to the right or left the currently selected tab.
|
|
|
|
void TerminalPage::_SelectNextTab(const bool bMoveRight)
|
|
|
|
{
|
2021-01-19 23:18:10 +01:00
|
|
|
const auto index{ _GetFocusedTabIndex().value_or(0) };
|
2020-11-05 15:28:16 +01:00
|
|
|
const auto tabSwitchMode = _settings.GlobalSettings().TabSwitcherMode();
|
2021-01-19 23:18:10 +01:00
|
|
|
if (tabSwitchMode == TabSwitcherMode::Disabled)
|
2020-11-05 15:28:16 +01:00
|
|
|
{
|
2021-01-19 23:18:10 +01:00
|
|
|
uint32_t tabCount = _tabs.Size();
|
|
|
|
// Wraparound math. By adding tabCount and then calculating
|
|
|
|
// modulo tabCount, we clamp the values to the range [0,
|
|
|
|
// tabCount) while still supporting moving leftward from 0 to
|
|
|
|
// tabCount - 1.
|
|
|
|
const auto newTabIndex = ((tabCount + index + (bMoveRight ? 1 : -1)) % tabCount);
|
|
|
|
_SelectTab(newTabIndex);
|
2020-11-05 15:28:16 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-19 23:18:10 +01:00
|
|
|
CommandPalette().SetTabs(_tabs, _mruTabs);
|
2020-08-21 17:39:40 +02:00
|
|
|
|
2020-11-13 02:33:50 +01:00
|
|
|
// Otherwise, set up the tab switcher in the selected mode, with
|
|
|
|
// the given ordering, and make it visible.
|
2021-01-19 23:18:10 +01:00
|
|
|
CommandPalette().EnableTabSwitcherMode(index, tabSwitchMode);
|
2020-11-13 02:33:50 +01:00
|
|
|
CommandPalette().Visibility(Visibility::Visible);
|
2021-01-19 23:18:10 +01:00
|
|
|
CommandPalette().SelectNextItem(bMoveRight);
|
2020-10-21 21:37:28 +02:00
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Sets focus to the desired tab. Returns false if the provided tabIndex
|
|
|
|
// is greater than the number of tabs we have.
|
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
|
|
|
// - During startup, we'll immediately set the selected tab as focused.
|
|
|
|
// - After startup, we'll dispatch an async method to set the the selected
|
|
|
|
// item of the TabView, which will then also trigger a
|
|
|
|
// TabView::SelectionChanged, handled in
|
|
|
|
// TerminalPage::_OnTabSelectionChanged
|
2019-09-04 23:34:06 +02:00
|
|
|
// Return Value:
|
|
|
|
// true iff we were able to select that tab index, false otherwise
|
2020-02-04 22:51:11 +01:00
|
|
|
bool TerminalPage::_SelectTab(const uint32_t tabIndex)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-02-04 22:51:11 +01:00
|
|
|
if (tabIndex >= 0 && tabIndex < _tabs.Size())
|
2019-09-04 23:34:06 +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
|
|
|
if (_startupState == StartupState::InStartup)
|
|
|
|
{
|
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 tab{ _tabs.GetAt(tabIndex) };
|
|
|
|
_tabView.SelectedItem(tab.TabViewItem());
|
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
|
|
|
_UpdatedSelectedTab(tabIndex);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_SetFocusedTabIndex(tabIndex);
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-08-08 01:11:44 +02:00
|
|
|
// 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()
|
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto activeTab{ _GetFocusedTabImpl() })
|
2020-08-08 01:11:44 +02:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
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
|
|
|
{
|
2021-01-04 20:32:53 +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
|
|
|
}
|
2020-08-08 01:11:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02: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:
|
|
|
|
// - <none>
|
Support for navigating panes by MRU (#8183)
Adds a "move to previous pane" and "move to next pane" keybinding, which
navigates to the last/first focused pane
We assign pane IDs on creation and maintain a vector of active pane IDs
in MRU order. Navigating panes by MRU then requires specifying which
pane ID we want to focus.
From our offline discussion (thanks @zadjii-msft for the concise
description):
> For the record, the full spec I'm imagining is:
>
> { command": { "action": "focus(Next|Prev)Pane", "order": "inOrder"|"mru", "useSwitcher": true|false } },
>
> and order defaults to mru, and useSwitcher will default to true, when
> there is a switcher. So
>
> { command": { "action": "focusNextPane" } },
> { command": { "action": "focusNextPane", "order": "mru" } },
>
> these are the same action. (but right now we don't support the order
> param)
>
> Then there'll be another PR for "focusPane(target=id)"
>
> Then a third PR for "focus(Next|Prev)Pane(order=inOrder)"
> for the record, I prefer this approach over the "one action to rule
> them all" version with both target and order/direction as params,
> because I don't like the confusion of what happens if there's both
> target and order/direction provided.
References #1000
Closes #2871
2020-12-11 19:36:05 +01:00
|
|
|
void TerminalPage::_MoveFocus(const FocusDirection& direction)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
2020-02-04 22:51:11 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
_UnZoomIfNeeded();
|
|
|
|
terminalTab->NavigateFocus(direction);
|
2020-02-04 22:51:11 +01:00
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-08-07 16:46:52 +02:00
|
|
|
TermControl TerminalPage::_GetActiveControl()
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
2020-02-04 22:51:11 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
return terminalTab->GetActiveTerminalControl();
|
2020-02-04 22:51:11 +01:00
|
|
|
}
|
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;
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Returns the index in our list of tabs of the currently focused tab. If
|
2020-08-25 21:25:25 +02:00
|
|
|
// no tab is currently selected, returns nullopt.
|
2019-09-04 23:34:06 +02:00
|
|
|
// Return Value:
|
2020-08-25 21:25:25 +02:00
|
|
|
// - the index of the currently focused tab if there is one, else nullopt
|
2020-02-04 22:51:11 +01:00
|
|
|
std::optional<uint32_t> TerminalPage::_GetFocusedTabIndex() const noexcept
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
// GH#1117: This is a workaround because _tabView.SelectedIndex()
|
|
|
|
// sometimes return incorrect result after removing some tabs
|
|
|
|
uint32_t focusedIndex;
|
2019-10-15 07:41:43 +02:00
|
|
|
if (_tabView.TabItems().IndexOf(_tabView.SelectedItem(), focusedIndex))
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
return focusedIndex;
|
|
|
|
}
|
2020-02-04 22:51:11 +01:00
|
|
|
return std::nullopt;
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-06-24 22:07:41 +02:00
|
|
|
// Method Description:
|
|
|
|
// - returns a com_ptr to the currently focused tab. This might return null,
|
|
|
|
// so make sure to check the result!
|
2021-01-04 20:32:53 +01:00
|
|
|
winrt::TerminalApp::TabBase TerminalPage::_GetFocusedTab() const noexcept
|
2020-06-24 22:07:41 +02:00
|
|
|
{
|
|
|
|
if (auto index{ _GetFocusedTabIndex() })
|
|
|
|
{
|
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 _tabs.GetAt(*index);
|
2020-06-24 22:07:41 +02:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-01-04 20:32:53 +01:00
|
|
|
// Method Description:
|
|
|
|
// - returns a com_ptr to the currently focused tab implementation. This might return null,
|
|
|
|
// so make sure to check the result!
|
|
|
|
winrt::com_ptr<TerminalTab> TerminalPage::_GetFocusedTabImpl() const noexcept
|
|
|
|
{
|
|
|
|
if (auto tab{ _GetFocusedTab() })
|
|
|
|
{
|
|
|
|
return _GetTerminalTabImpl(tab);
|
|
|
|
}
|
|
|
|
return 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
|
|
|
// Method Description:
|
|
|
|
// - An async method for changing the focused tab on the UI thread. This
|
|
|
|
// method will _only_ set the selected item of the TabView, which will
|
|
|
|
// then also trigger a TabView::SelectionChanged event, which we'll handle
|
|
|
|
// in TerminalPage::_OnTabSelectionChanged, where we'll mark the new tab
|
|
|
|
// as focused.
|
|
|
|
// Arguments:
|
|
|
|
// - tabIndex: the index in the list of tabs to focus.
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
2020-02-04 22:51:11 +01:00
|
|
|
winrt::fire_and_forget TerminalPage::_SetFocusedTabIndex(const uint32_t tabIndex)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
// GH#1117: This is a workaround because _tabView.SelectedIndex(tabIndex)
|
|
|
|
// sometimes set focus to an incorrect tab after removing some tabs
|
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 weakThis{ get_weak() };
|
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(_tabView.Dispatcher());
|
|
|
|
|
|
|
|
if (auto page{ weakThis.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
|
|
|
auto tabToFocus = page->_tabs.GetAt(tabIndex);
|
|
|
|
_tabView.SelectedItem(tabToFocus.TabViewItem());
|
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
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Close the currently focused tab. Focus will move to the left, if possible.
|
|
|
|
void TerminalPage::_CloseFocusedTab()
|
|
|
|
{
|
2020-02-04 22:51:11 +01:00
|
|
|
if (auto index{ _GetFocusedTabIndex() })
|
|
|
|
{
|
|
|
|
_RemoveTabViewItemByIndex(*index);
|
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Close the currently focused pane. If the pane is the last pane in the
|
|
|
|
// tab, the tab will also be closed. This will happen when we handle the
|
|
|
|
// tab's Closed event.
|
|
|
|
void TerminalPage::_CloseFocusedPane()
|
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
2020-02-04 22:51:11 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
_UnZoomIfNeeded();
|
|
|
|
terminalTab->ClosePane();
|
2020-02-04 22:51:11 +01:00
|
|
|
}
|
2021-01-26 20:14:28 +01:00
|
|
|
else if (auto index{ _GetFocusedTabIndex() })
|
|
|
|
{
|
|
|
|
if (_tabs.GetAt(*index).try_as<TerminalApp::SettingsTab>())
|
|
|
|
{
|
|
|
|
_RemoveTabViewItemByIndex(*index);
|
|
|
|
}
|
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2019-09-17 07:43:27 +02:00
|
|
|
// Method Description:
|
2019-10-11 02:09:07 +02:00
|
|
|
// - Close the terminal app. If there is more
|
2019-09-17 07:43:27 +02:00
|
|
|
// than one tab opened, show a warning dialog.
|
2020-11-20 18:40:33 +01:00
|
|
|
fire_and_forget TerminalPage::CloseWindow()
|
2019-09-17 07:43:27 +02:00
|
|
|
{
|
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
|
|
|
if (_tabs.Size() > 1 && _settings.GlobalSettings().ConfirmCloseAllTabs() && !_displayingCloseDialog)
|
2019-09-17 07:43:27 +02:00
|
|
|
{
|
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;
|
2020-11-20 18:40:33 +01:00
|
|
|
ContentDialogResult warningResult = co_await _ShowCloseWarningDialog();
|
|
|
|
_displayingCloseDialog = false;
|
|
|
|
|
|
|
|
if (warningResult != ContentDialogResult::Primary)
|
|
|
|
{
|
|
|
|
co_return;
|
|
|
|
}
|
2019-09-17 07:43:27 +02:00
|
|
|
}
|
2020-11-20 18:40:33 +01:00
|
|
|
|
|
|
|
_CloseAllTabs();
|
2019-09-17 07:43:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Remove all the tabs opened and the terminal will terminate
|
|
|
|
// on its own when the last tab is closed.
|
|
|
|
void TerminalPage::_CloseAllTabs()
|
|
|
|
{
|
2020-02-04 22:51:11 +01:00
|
|
|
while (_tabs.Size() != 0)
|
2019-09-17 07:43:27 +02:00
|
|
|
{
|
|
|
|
_RemoveTabViewItemByIndex(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Move the viewport of the terminal of the currently focused tab up or
|
2020-10-27 02:19:52 +01:00
|
|
|
// down a number of lines.
|
2019-09-04 23:34:06 +02:00
|
|
|
// Arguments:
|
2020-10-27 02:19:52 +01:00
|
|
|
// - 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)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
2020-02-04 22:51:11 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
uint32_t realRowsToScroll;
|
|
|
|
if (rowsToScroll == nullptr)
|
2020-10-27 02:19:52 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
|
|
|
|
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
|
|
|
|
terminalTab->GetActiveTerminalControl().GetViewHeight() :
|
|
|
|
_systemRowsToScroll;
|
2020-10-27 02:19:52 +01:00
|
|
|
}
|
2021-01-04 20:32:53 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// use the custom value specified in the command
|
|
|
|
realRowsToScroll = rowsToScroll.Value();
|
|
|
|
}
|
|
|
|
auto scrollDelta = _ComputeScrollDelta(scrollDirection, realRowsToScroll);
|
|
|
|
terminalTab->Scroll(scrollDelta);
|
2020-02-04 22:51:11 +01:00
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Split the focused pane either horizontally or vertically, and place the
|
|
|
|
// given TermControl into the newly created pane.
|
|
|
|
// - If splitType == SplitState::None, this method does nothing.
|
|
|
|
// Arguments:
|
2019-11-28 14:42:15 +01:00
|
|
|
// - splitType: one value from the TerminalApp::SplitState enum, indicating how the
|
2019-09-04 23:34:06 +02:00
|
|
|
// new pane should be split from its parent.
|
2020-03-07 00:15:45 +01:00
|
|
|
// - 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.
|
2020-10-06 18:56:59 +02:00
|
|
|
void TerminalPage::_SplitPane(const SplitState splitType,
|
|
|
|
const SplitType splitMode,
|
Add `size` param to `splitPane` action, `split-pane` subcommand (#8543)
## Summary of the Pull Request
Adds a `size` parameter to `splitPane`. This takes a `float`, and specifies the portion of the parent pane that should be used to create the new one.
This also adds the param to the `split-pane` subcommand.
### Examples
| commandline | result |
| -- | -- |
| `wt ; sp -s .25` | ![image](https://user-images.githubusercontent.com/18356694/101784317-fb595680-3ac0-11eb-8248-782dc61957cf.png) |
| `wt ; sp -s .8` | ![image](https://user-images.githubusercontent.com/18356694/101784442-20e66000-3ac1-11eb-8f9b-fb45a73c9334.png) |
| `wt ; sp -s .8 ; sp -H -s .3` | ![image](https://user-images.githubusercontent.com/18356694/101784552-470c0000-3ac1-11eb-9deb-df37aaa36f01.png) |
## PR Checklist
* [x] Closes #6298
* [x] I work here
* [x] Tests added/passed
* [x] Docs PR: MicrosoftDocs/terminal#208
## Detailed Description of the Pull Request / Additional comments
I went with `size`, `--size,-s` rather than `percent`, because the arg is the (0,1) version of the size, not the (0%,100%) version.
## Validation Steps Performed
Added actions, played with the commandline, ran tests
2020-12-18 04:51:53 +01:00
|
|
|
const float splitSize,
|
2020-10-06 18:56:59 +02:00
|
|
|
const NewTerminalArgs& newTerminalArgs)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
// Do nothing if we're requesting no split.
|
2020-10-06 18:56:59 +02:00
|
|
|
if (splitType == SplitState::None)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-04 20:32:53 +01:00
|
|
|
const auto focusedTab{ _GetFocusedTabImpl() };
|
2020-02-04 22:51:11 +01:00
|
|
|
|
2021-01-04 20:32:53 +01:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
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
|
2020-03-07 00:15:45 +01:00
|
|
|
{
|
2020-08-04 00:54:22 +02:00
|
|
|
TerminalApp::TerminalSettings controlSettings;
|
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
|
|
|
GUID realGuid;
|
|
|
|
bool profileFound = false;
|
|
|
|
|
2020-10-06 18:56:59 +02:00
|
|
|
if (splitMode == SplitType::Duplicate)
|
2020-03-07 00:15:45 +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
|
|
|
std::optional<GUID> current_guid = focusedTab->GetFocusedProfile();
|
|
|
|
if (current_guid)
|
|
|
|
{
|
|
|
|
profileFound = true;
|
2020-09-14 22:38:56 +02:00
|
|
|
controlSettings = { winrt::make<TerminalSettings>(_settings, current_guid.value(), *_bindings) };
|
2021-01-11 19:01:38 +01:00
|
|
|
const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory();
|
|
|
|
const auto validWorkingDirectory = !workingDirectory.empty();
|
|
|
|
if (validWorkingDirectory)
|
|
|
|
{
|
|
|
|
controlSettings.StartingDirectory(workingDirectory);
|
|
|
|
}
|
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
|
|
|
realGuid = current_guid.value();
|
|
|
|
}
|
|
|
|
// 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 (!profileFound)
|
|
|
|
{
|
2020-09-14 22:38:56 +02:00
|
|
|
std::tie(realGuid, controlSettings) = TerminalSettings::BuildSettings(_settings, newTerminalArgs, *_bindings);
|
2020-03-07 00:15:45 +01:00
|
|
|
}
|
2019-09-04 23:34:06 +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
|
|
|
const auto controlConnection = _CreateConnectionFromSettings(realGuid, controlSettings);
|
2019-09-04 23:34:06 +02: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
|
|
|
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 };
|
2019-09-04 23:34:06 +02: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
|
|
|
auto realSplitType = splitType;
|
|
|
|
if (realSplitType == SplitState::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 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
|
|
|
realSplitType = focusedTab->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
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
|
Add `size` param to `splitPane` action, `split-pane` subcommand (#8543)
## Summary of the Pull Request
Adds a `size` parameter to `splitPane`. This takes a `float`, and specifies the portion of the parent pane that should be used to create the new one.
This also adds the param to the `split-pane` subcommand.
### Examples
| commandline | result |
| -- | -- |
| `wt ; sp -s .25` | ![image](https://user-images.githubusercontent.com/18356694/101784317-fb595680-3ac0-11eb-8248-782dc61957cf.png) |
| `wt ; sp -s .8` | ![image](https://user-images.githubusercontent.com/18356694/101784442-20e66000-3ac1-11eb-8f9b-fb45a73c9334.png) |
| `wt ; sp -s .8 ; sp -H -s .3` | ![image](https://user-images.githubusercontent.com/18356694/101784552-470c0000-3ac1-11eb-9deb-df37aaa36f01.png) |
## PR Checklist
* [x] Closes #6298
* [x] I work here
* [x] Tests added/passed
* [x] Docs PR: MicrosoftDocs/terminal#208
## Detailed Description of the Pull Request / Additional comments
I went with `size`, `--size,-s` rather than `percent`, because the arg is the (0,1) version of the size, not the (0%,100%) version.
## Validation Steps Performed
Added actions, played with the commandline, ran tests
2020-12-18 04:51:53 +01:00
|
|
|
const auto canSplit = focusedTab->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
|
|
|
}
|
2019-09-04 23:34:06 +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
|
|
|
TermControl newControl{ controlSettings, controlConnection };
|
2019-09-04 23:34:06 +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
|
|
|
// Hookup our event handlers to the new terminal
|
|
|
|
_RegisterTerminalEvents(newControl, *focusedTab);
|
|
|
|
|
2020-08-08 01:11:44 +02:00
|
|
|
_UnZoomIfNeeded();
|
|
|
|
|
Add `size` param to `splitPane` action, `split-pane` subcommand (#8543)
## Summary of the Pull Request
Adds a `size` parameter to `splitPane`. This takes a `float`, and specifies the portion of the parent pane that should be used to create the new one.
This also adds the param to the `split-pane` subcommand.
### Examples
| commandline | result |
| -- | -- |
| `wt ; sp -s .25` | ![image](https://user-images.githubusercontent.com/18356694/101784317-fb595680-3ac0-11eb-8248-782dc61957cf.png) |
| `wt ; sp -s .8` | ![image](https://user-images.githubusercontent.com/18356694/101784442-20e66000-3ac1-11eb-8f9b-fb45a73c9334.png) |
| `wt ; sp -s .8 ; sp -H -s .3` | ![image](https://user-images.githubusercontent.com/18356694/101784552-470c0000-3ac1-11eb-9deb-df37aaa36f01.png) |
## PR Checklist
* [x] Closes #6298
* [x] I work here
* [x] Tests added/passed
* [x] Docs PR: MicrosoftDocs/terminal#208
## Detailed Description of the Pull Request / Additional comments
I went with `size`, `--size,-s` rather than `percent`, because the arg is the (0,1) version of the size, not the (0%,100%) version.
## Validation Steps Performed
Added actions, played with the commandline, ran tests
2020-12-18 04:51:53 +01:00
|
|
|
focusedTab->SplitPane(realSplitType, splitSize, realGuid, 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
|
|
|
}
|
|
|
|
CATCH_LOG();
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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>
|
Support for navigating panes by MRU (#8183)
Adds a "move to previous pane" and "move to next pane" keybinding, which
navigates to the last/first focused pane
We assign pane IDs on creation and maintain a vector of active pane IDs
in MRU order. Navigating panes by MRU then requires specifying which
pane ID we want to focus.
From our offline discussion (thanks @zadjii-msft for the concise
description):
> For the record, the full spec I'm imagining is:
>
> { command": { "action": "focus(Next|Prev)Pane", "order": "inOrder"|"mru", "useSwitcher": true|false } },
>
> and order defaults to mru, and useSwitcher will default to true, when
> there is a switcher. So
>
> { command": { "action": "focusNextPane" } },
> { command": { "action": "focusNextPane", "order": "mru" } },
>
> these are the same action. (but right now we don't support the order
> param)
>
> Then there'll be another PR for "focusPane(target=id)"
>
> Then a third PR for "focus(Next|Prev)Pane(order=inOrder)"
> for the record, I prefer this approach over the "one action to rule
> them all" version with both target and order/direction as params,
> because I don't like the confusion of what happens if there's both
> target and order/direction provided.
References #1000
Closes #2871
2020-12-11 19:36:05 +01:00
|
|
|
void TerminalPage::_ResizePane(const ResizeDirection& direction)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
2020-02-04 22:51:11 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
_UnZoomIfNeeded();
|
|
|
|
terminalTab->ResizePane(direction);
|
2020-02-04 22:51:11 +01:00
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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:
|
2020-10-27 02:19:52 +01:00
|
|
|
// - scrollDirection: ScrollUp will move the viewport up, ScrollDown will move the viewport down
|
|
|
|
void TerminalPage::_ScrollPage(ScrollDirection scrollDirection)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
// 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
|
|
|
{
|
|
|
|
const auto control = _GetActiveControl();
|
|
|
|
const auto termHeight = control.GetViewHeight();
|
|
|
|
auto scrollDelta = _ComputeScrollDelta(scrollDirection, termHeight);
|
|
|
|
terminalTab->Scroll(scrollDelta);
|
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-12-08 18:28:41 +01:00
|
|
|
void TerminalPage::_ScrollToBufferEdge(ScrollDirection scrollDirection)
|
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
2020-12-08 18:28:41 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
auto scrollDelta = _ComputeScrollDelta(scrollDirection, INT_MAX);
|
|
|
|
terminalTab->Scroll(scrollDelta);
|
2020-12-08 18:28:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// 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()
|
|
|
|
{
|
2020-09-09 22:49:53 +02:00
|
|
|
if (_settings.GlobalSettings().ShowTitleInTitlebar())
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
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() })
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
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
|
2020-08-07 16:46:52 +02:00
|
|
|
static std::wstring _FormatOverrideShortcutText(KeyModifiers modifiers)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
std::wstring buffer{ L"" };
|
|
|
|
|
2020-08-07 16:46:52 +02:00
|
|
|
if (WI_IsFlagSet(modifiers, KeyModifiers::Ctrl))
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
buffer += L"Ctrl+";
|
|
|
|
}
|
|
|
|
|
2020-08-07 16:46:52 +02:00
|
|
|
if (WI_IsFlagSet(modifiers, KeyModifiers::Shift))
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
buffer += L"Shift+";
|
|
|
|
}
|
|
|
|
|
2020-08-07 16:46:52 +02:00
|
|
|
if (WI_IsFlagSet(modifiers, KeyModifiers::Alt))
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
buffer += L"Alt+";
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2019-10-15 07:41:43 +02:00
|
|
|
void TerminalPage::_SetAcceleratorForMenuItem(WUX::Controls::MenuFlyoutItem& menuItem,
|
2020-08-07 16:46:52 +02:00
|
|
|
const KeyChord& keyChord)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
#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()));
|
|
|
|
|
|
|
|
// inspect the modifiers from the KeyChord and set the flags int he XAML value
|
|
|
|
auto modifiers = AppKeyBindings::ConvertVKModifiers(keyChord.Modifiers());
|
|
|
|
|
|
|
|
// add the modifiers to the shortcut
|
|
|
|
menuShortcut.Modifiers(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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-08 22:19:23 +01:00
|
|
|
// Method Description:
|
2020-02-10 21:40:01 +01:00
|
|
|
// - Calculates the appropriate size to snap to in the given direction, for
|
2020-01-09 18:19:21 +01:00
|
|
|
// the given dimension. If the global setting `snapToGridOnResize` is set
|
|
|
|
// to `false`, this will just immediately return the provided dimension,
|
|
|
|
// effectively disabling snapping.
|
2020-01-08 22:19:23 +01:00
|
|
|
// - See Pane::CalcSnappedDimension
|
|
|
|
float TerminalPage::CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
|
|
|
|
{
|
Prevent resizing terminal to a lower-than-minimum width (#8066)
Until now, we relied on WM_SIZING to ensure that the island is not
downsized below minimal allowed dimensions. However, on some occasions
WM_WINDOWPOSCHANGED, e.g. when anchoring a window to the top/bottom of
the screen. This message will use dimensions obtained from
WM_GETMINMAXINFO. Until now we didn't override this value, falling back
to the defaults. As a result we got an inconsistent behavior (at least
when attaching the anchor).
I added logic very similar to the one we use in IslandWindow::_OnSizing
to the MINMAXINFO handler: snap the client area, add non client
exclusive are, consider DPI along the computation.
## Validation Steps Performed
* Manual testing of minimizing, maximizing, resizing, attaching
different anchors, etc.
Closes #8026
2020-11-13 04:15:46 +01:00
|
|
|
if (_settings && _settings.GlobalSettings().SnapToGridOnResize())
|
2020-01-09 18:19:21 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
2020-02-04 22:51:11 +01:00
|
|
|
{
|
2021-01-04 20:32:53 +01:00
|
|
|
return terminalTab->CalcSnappedDimension(widthOrHeight, dimension);
|
2020-02-04 22:51:11 +01:00
|
|
|
}
|
2020-01-09 18:19:21 +01:00
|
|
|
}
|
2020-02-04 22:51:11 +01:00
|
|
|
return dimension;
|
2020-01-08 22:19:23 +01:00
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02: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*/,
|
2020-08-07 16:46:52 +02:00
|
|
|
const CopyToClipboardEventArgs copiedData)
|
2019-09-04 23:34:06 +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
|
|
|
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::High);
|
2019-09-04 23:34:06 +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
|
|
|
DataPackage dataPack = DataPackage();
|
|
|
|
dataPack.RequestedOperation(DataPackageOperation::Copy);
|
2019-09-04 23:34:06 +02:00
|
|
|
|
Add copyFormatting keybinding arg and array support (#6004)
Adds array support for the existing `copyFormatting` global setting.
This allows users to define which formats they would specifically like
to be copied.
A boolean value is still accepted and is translated to the following:
- `false` --> `"none"` or `[]`
- `true` --> `"all"` or `["html", "rtf"]`
This also adds `copyFormatting` as a keybinding arg for `copy`. As with
the global setting, a boolean value and array value is accepted.
CopyFormat is a WinRT enum where each accepted format is a flag.
Currently accepted formats include `html`, and `rtf`. A boolean value is
accepted and converted. `true` is a conjunction of all the formats.
`false` only includes plain text.
For the global setting, `null` is not accepted. We already have a
default value from before so no worries there.
For the keybinding arg, `null` (the default value) means that we just do
what the global arg says to do. Overall, the `copyFormatting` keybinding
arg is an override of the global setting **when using that keybinding**.
References #5212 - Spec for formatted copying
References #2690 - disable html copy
Validated behavior with every combination of values below:
- `copyFormatting` global: { `true`, `false`, `[]`, `["html"]` }
- `copyFormatting` copy arg:
{ `null`, `true`, `false`, `[]`, `[, "html"]`}
Closes #4191
Closes #5262
2020-08-15 03:02:24 +02:00
|
|
|
// The EventArgs.Formats() is an override for the global setting "copyFormatting"
|
|
|
|
// iff it is set
|
|
|
|
bool useGlobal = copiedData.Formats() == nullptr;
|
|
|
|
auto copyFormats = useGlobal ?
|
2020-09-09 22:49:53 +02:00
|
|
|
_settings.GlobalSettings().CopyFormatting() :
|
Add copyFormatting keybinding arg and array support (#6004)
Adds array support for the existing `copyFormatting` global setting.
This allows users to define which formats they would specifically like
to be copied.
A boolean value is still accepted and is translated to the following:
- `false` --> `"none"` or `[]`
- `true` --> `"all"` or `["html", "rtf"]`
This also adds `copyFormatting` as a keybinding arg for `copy`. As with
the global setting, a boolean value and array value is accepted.
CopyFormat is a WinRT enum where each accepted format is a flag.
Currently accepted formats include `html`, and `rtf`. A boolean value is
accepted and converted. `true` is a conjunction of all the formats.
`false` only includes plain text.
For the global setting, `null` is not accepted. We already have a
default value from before so no worries there.
For the keybinding arg, `null` (the default value) means that we just do
what the global arg says to do. Overall, the `copyFormatting` keybinding
arg is an override of the global setting **when using that keybinding**.
References #5212 - Spec for formatted copying
References #2690 - disable html copy
Validated behavior with every combination of values below:
- `copyFormatting` global: { `true`, `false`, `[]`, `["html"]` }
- `copyFormatting` copy arg:
{ `null`, `true`, `false`, `[]`, `[, "html"]`}
Closes #4191
Closes #5262
2020-08-15 03:02:24 +02:00
|
|
|
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());
|
2019-09-04 23:34:06 +02:00
|
|
|
|
Add copyFormatting keybinding arg and array support (#6004)
Adds array support for the existing `copyFormatting` global setting.
This allows users to define which formats they would specifically like
to be copied.
A boolean value is still accepted and is translated to the following:
- `false` --> `"none"` or `[]`
- `true` --> `"all"` or `["html", "rtf"]`
This also adds `copyFormatting` as a keybinding arg for `copy`. As with
the global setting, a boolean value and array value is accepted.
CopyFormat is a WinRT enum where each accepted format is a flag.
Currently accepted formats include `html`, and `rtf`. A boolean value is
accepted and converted. `true` is a conjunction of all the formats.
`false` only includes plain text.
For the global setting, `null` is not accepted. We already have a
default value from before so no worries there.
For the keybinding arg, `null` (the default value) means that we just do
what the global arg says to do. Overall, the `copyFormatting` keybinding
arg is an override of the global setting **when using that keybinding**.
References #5212 - Spec for formatted copying
References #2690 - disable html copy
Validated behavior with every combination of values below:
- `copyFormatting` global: { `true`, `false`, `[]`, `["html"]` }
- `copyFormatting` copy arg:
{ `null`, `true`, `false`, `[]`, `[, "html"]`}
Closes #4191
Closes #5262
2020-08-15 03:02:24 +02:00
|
|
|
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
|
|
|
{
|
2020-04-10 01:32:38 +02:00
|
|
|
// copy html to dataPack
|
|
|
|
const auto htmlData = copiedData.Html();
|
|
|
|
if (!htmlData.empty())
|
|
|
|
{
|
|
|
|
dataPack.SetHtmlFormat(htmlData);
|
|
|
|
}
|
Add copyFormatting keybinding arg and array support (#6004)
Adds array support for the existing `copyFormatting` global setting.
This allows users to define which formats they would specifically like
to be copied.
A boolean value is still accepted and is translated to the following:
- `false` --> `"none"` or `[]`
- `true` --> `"all"` or `["html", "rtf"]`
This also adds `copyFormatting` as a keybinding arg for `copy`. As with
the global setting, a boolean value and array value is accepted.
CopyFormat is a WinRT enum where each accepted format is a flag.
Currently accepted formats include `html`, and `rtf`. A boolean value is
accepted and converted. `true` is a conjunction of all the formats.
`false` only includes plain text.
For the global setting, `null` is not accepted. We already have a
default value from before so no worries there.
For the keybinding arg, `null` (the default value) means that we just do
what the global arg says to do. Overall, the `copyFormatting` keybinding
arg is an override of the global setting **when using that keybinding**.
References #5212 - Spec for formatted copying
References #2690 - disable html copy
Validated behavior with every combination of values below:
- `copyFormatting` global: { `true`, `false`, `[]`, `["html"]` }
- `copyFormatting` copy arg:
{ `null`, `true`, `false`, `[]`, `[, "html"]`}
Closes #4191
Closes #5262
2020-08-15 03:02:24 +02:00
|
|
|
}
|
2019-11-13 21:13:22 +01:00
|
|
|
|
Add copyFormatting keybinding arg and array support (#6004)
Adds array support for the existing `copyFormatting` global setting.
This allows users to define which formats they would specifically like
to be copied.
A boolean value is still accepted and is translated to the following:
- `false` --> `"none"` or `[]`
- `true` --> `"all"` or `["html", "rtf"]`
This also adds `copyFormatting` as a keybinding arg for `copy`. As with
the global setting, a boolean value and array value is accepted.
CopyFormat is a WinRT enum where each accepted format is a flag.
Currently accepted formats include `html`, and `rtf`. A boolean value is
accepted and converted. `true` is a conjunction of all the formats.
`false` only includes plain text.
For the global setting, `null` is not accepted. We already have a
default value from before so no worries there.
For the keybinding arg, `null` (the default value) means that we just do
what the global arg says to do. Overall, the `copyFormatting` keybinding
arg is an override of the global setting **when using that keybinding**.
References #5212 - Spec for formatted copying
References #2690 - disable html copy
Validated behavior with every combination of values below:
- `copyFormatting` global: { `true`, `false`, `[]`, `["html"]` }
- `copyFormatting` copy arg:
{ `null`, `true`, `false`, `[]`, `[, "html"]`}
Closes #4191
Closes #5262
2020-08-15 03:02:24 +02:00
|
|
|
if (WI_IsFlagSet(copyFormats, CopyFormat::RTF))
|
|
|
|
{
|
2020-04-10 01:32:38 +02:00
|
|
|
// 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();
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Function Description:
|
2020-07-01 21:43:28 +02:00
|
|
|
// - 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.
|
2019-09-04 23:34:06 +02:00
|
|
|
// Arguments:
|
|
|
|
// - eventArgs: the PasteFromClipboard event sent from the TermControl
|
2020-07-01 21:43:28 +02:00
|
|
|
fire_and_forget TerminalPage::_PasteFromClipboardHandler(const IInspectable /*sender*/,
|
|
|
|
const PasteFromClipboardEventArgs eventArgs)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
|
2020-05-12 20:23:58 +02:00
|
|
|
try
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-05-12 20:23:58 +02:00
|
|
|
hstring text = L"";
|
|
|
|
if (data.Contains(StandardDataFormats::Text()))
|
|
|
|
{
|
|
|
|
text = co_await data.GetTextAsync();
|
|
|
|
}
|
2020-05-27 19:42:49 +02:00
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
}
|
2020-07-01 21:43:28 +02:00
|
|
|
|
2021-01-08 11:44:16 +01:00
|
|
|
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();
|
|
|
|
const auto warnMultiLine = hasNewLine && _settings.GlobalSettings().WarnAboutMultiLinePaste();
|
2020-07-01 21:43:28 +02:00
|
|
|
|
|
|
|
constexpr const std::size_t minimumSizeForWarning = 1024 * 5; // 5 KiB
|
|
|
|
const bool warnLargeText = text.size() > minimumSizeForWarning &&
|
2020-09-09 22:49:53 +02:00
|
|
|
_settings.GlobalSettings().WarnAboutLargePaste();
|
2020-07-01 21:43:28 +02:00
|
|
|
|
|
|
|
if (warnMultiLine || warnLargeText)
|
|
|
|
{
|
|
|
|
co_await winrt::resume_foreground(Dispatcher());
|
|
|
|
|
2021-01-13 00:00:27 +01:00
|
|
|
// 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);
|
|
|
|
|
2020-07-01 21:43:28 +02:00
|
|
|
ContentDialogResult warningResult;
|
|
|
|
if (warnMultiLine)
|
|
|
|
{
|
|
|
|
warningResult = co_await _ShowMultiLinePasteWarningDialog();
|
|
|
|
}
|
|
|
|
else if (warnLargeText)
|
|
|
|
{
|
|
|
|
warningResult = co_await _ShowLargePasteWarningDialog();
|
|
|
|
}
|
|
|
|
|
2021-01-13 00:00:27 +01:00
|
|
|
// Clear the clipboard text so it doesn't lie around in memory
|
|
|
|
ClipboardText().Text(L"");
|
|
|
|
|
2020-07-01 21:43:28 +02:00
|
|
|
if (warningResult != ContentDialogResult::Primary)
|
|
|
|
{
|
|
|
|
// user rejected the paste
|
|
|
|
co_return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 20:23:58 +02:00
|
|
|
eventArgs.HandleClipboardData(text);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
2020-05-12 20:23:58 +02:00
|
|
|
CATCH_LOG();
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-09-03 19:52:39 +02:00
|
|
|
void TerminalPage::_OpenHyperlinkHandler(const IInspectable /*sender*/, const Microsoft::Terminal::TerminalControl::OpenHyperlinkEventArgs eventArgs)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto parsed = winrt::Windows::Foundation::Uri(eventArgs.Uri().c_str());
|
|
|
|
if (parsed.SchemeName() == L"http" || parsed.SchemeName() == L"https")
|
|
|
|
{
|
|
|
|
ShellExecute(nullptr, L"open", eventArgs.Uri().c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
|
|
|
}
|
2020-09-11 02:55:36 +02:00
|
|
|
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);
|
2020-09-03 19:52:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 03:24:06 +01:00
|
|
|
void TerminalPage::_ControlNoticeRaisedHandler(const IInspectable /*sender*/, const Microsoft::Terminal::TerminalControl::NoticeEventArgs eventArgs)
|
|
|
|
{
|
|
|
|
winrt::hstring message = eventArgs.Message();
|
|
|
|
|
|
|
|
winrt::hstring title;
|
|
|
|
|
|
|
|
switch (eventArgs.Level())
|
|
|
|
{
|
|
|
|
case TerminalControl::NoticeLevel::Debug:
|
|
|
|
title = RS_(L"NoticeDebug"); //\xebe8
|
|
|
|
break;
|
|
|
|
case TerminalControl::NoticeLevel::Info:
|
|
|
|
title = RS_(L"NoticeInfo"); // \xe946
|
|
|
|
break;
|
|
|
|
case TerminalControl::NoticeLevel::Warning:
|
|
|
|
title = RS_(L"NoticeWarning"); //\xe7ba
|
|
|
|
break;
|
|
|
|
case TerminalControl::NoticeLevel::Error:
|
|
|
|
title = RS_(L"NoticeError"); //\xe783
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Copy text from the focused terminal to the Windows Clipboard
|
|
|
|
// Arguments:
|
2020-04-03 01:10:28 +02:00
|
|
|
// - singleLine: if enabled, copy contents as a single line of text
|
Add copyFormatting keybinding arg and array support (#6004)
Adds array support for the existing `copyFormatting` global setting.
This allows users to define which formats they would specifically like
to be copied.
A boolean value is still accepted and is translated to the following:
- `false` --> `"none"` or `[]`
- `true` --> `"all"` or `["html", "rtf"]`
This also adds `copyFormatting` as a keybinding arg for `copy`. As with
the global setting, a boolean value and array value is accepted.
CopyFormat is a WinRT enum where each accepted format is a flag.
Currently accepted formats include `html`, and `rtf`. A boolean value is
accepted and converted. `true` is a conjunction of all the formats.
`false` only includes plain text.
For the global setting, `null` is not accepted. We already have a
default value from before so no worries there.
For the keybinding arg, `null` (the default value) means that we just do
what the global arg says to do. Overall, the `copyFormatting` keybinding
arg is an override of the global setting **when using that keybinding**.
References #5212 - Spec for formatted copying
References #2690 - disable html copy
Validated behavior with every combination of values below:
- `copyFormatting` global: { `true`, `false`, `[]`, `["html"]` }
- `copyFormatting` copy arg:
{ `null`, `true`, `false`, `[]`, `[, "html"]`}
Closes #4191
Closes #5262
2020-08-15 03:02:24 +02:00
|
|
|
// - formats: dictate which formats need to be copied
|
2019-09-04 23:34:06 +02:00
|
|
|
// Return Value:
|
|
|
|
// - true iff we we able to copy text (if a selection was active)
|
Add copyFormatting keybinding arg and array support (#6004)
Adds array support for the existing `copyFormatting` global setting.
This allows users to define which formats they would specifically like
to be copied.
A boolean value is still accepted and is translated to the following:
- `false` --> `"none"` or `[]`
- `true` --> `"all"` or `["html", "rtf"]`
This also adds `copyFormatting` as a keybinding arg for `copy`. As with
the global setting, a boolean value and array value is accepted.
CopyFormat is a WinRT enum where each accepted format is a flag.
Currently accepted formats include `html`, and `rtf`. A boolean value is
accepted and converted. `true` is a conjunction of all the formats.
`false` only includes plain text.
For the global setting, `null` is not accepted. We already have a
default value from before so no worries there.
For the keybinding arg, `null` (the default value) means that we just do
what the global arg says to do. Overall, the `copyFormatting` keybinding
arg is an override of the global setting **when using that keybinding**.
References #5212 - Spec for formatted copying
References #2690 - disable html copy
Validated behavior with every combination of values below:
- `copyFormatting` global: { `true`, `false`, `[]`, `["html"]` }
- `copyFormatting` copy arg:
{ `null`, `true`, `false`, `[]`, `[, "html"]`}
Closes #4191
Closes #5262
2020-08-15 03:02:24 +02:00
|
|
|
bool TerminalPage::_CopyText(const bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
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
|
|
|
const auto control = _GetActiveControl();
|
Add copyFormatting keybinding arg and array support (#6004)
Adds array support for the existing `copyFormatting` global setting.
This allows users to define which formats they would specifically like
to be copied.
A boolean value is still accepted and is translated to the following:
- `false` --> `"none"` or `[]`
- `true` --> `"all"` or `["html", "rtf"]`
This also adds `copyFormatting` as a keybinding arg for `copy`. As with
the global setting, a boolean value and array value is accepted.
CopyFormat is a WinRT enum where each accepted format is a flag.
Currently accepted formats include `html`, and `rtf`. A boolean value is
accepted and converted. `true` is a conjunction of all the formats.
`false` only includes plain text.
For the global setting, `null` is not accepted. We already have a
default value from before so no worries there.
For the keybinding arg, `null` (the default value) means that we just do
what the global arg says to do. Overall, the `copyFormatting` keybinding
arg is an override of the global setting **when using that keybinding**.
References #5212 - Spec for formatted copying
References #2690 - disable html copy
Validated behavior with every combination of values below:
- `copyFormatting` global: { `true`, `false`, `[]`, `["html"]` }
- `copyFormatting` copy arg:
{ `null`, `true`, `false`, `[]`, `[, "html"]`}
Closes #4191
Closes #5262
2020-08-15 03:02:24 +02:00
|
|
|
return control.CopySelectionToClipboard(singleLine, formats);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-11-18 23:24:11 +01:00
|
|
|
// 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
|
|
|
|
void TerminalPage::_SetTaskbarProgressHandler(const IInspectable /*sender*/, const IInspectable /*eventArgs*/)
|
|
|
|
{
|
|
|
|
_setTaskbarProgressHandlers(*this, nullptr);
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Paste text from the Windows Clipboard to the focused terminal
|
|
|
|
void TerminalPage::_PasteText()
|
|
|
|
{
|
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
|
|
|
const auto control = _GetActiveControl();
|
2019-09-04 23:34:06 +02:00
|
|
|
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.
|
Add keybinding arg to openSettings (#6299)
## Summary of the Pull Request
Adds the `target` keybinding arg to `openSettings`. Possible values include: `defaultsFile`, `settingsFile`, and `allFiles`.
## References
#5915 - mini-spec
## PR Checklist
* [x] Closes #2557
* [x] Tests added/passed
## Detailed Description of the Pull Request / Additional comments
Implemented as discussed in the attached spec. A new enum will be added for the SettingsUI when it becomes available.
## Validation Steps Performed
Added the following to my settings.json:
```json
{ "command": "openSettings", "keys":... },
{ "command": { "action": "openSettings" }, "keys":... },
{ "command": { "action": "openSettings", "target": "settingsFile" }, "keys":... },
{ "command": { "action": "openSettings", "target": "defaultsFile" }, "keys":... },
{ "command": { "action": "openSettings", "target": "allFiles" }, "keys":... }
```
2020-06-12 23:19:18 +02:00
|
|
|
fire_and_forget TerminalPage::_LaunchSettings(const SettingsTarget target)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-12-11 22:34:57 +01:00
|
|
|
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();
|
2019-09-04 23:34:06 +02:00
|
|
|
|
2020-12-11 22:34:57 +01:00
|
|
|
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)
|
Add keybinding arg to openSettings (#6299)
## Summary of the Pull Request
Adds the `target` keybinding arg to `openSettings`. Possible values include: `defaultsFile`, `settingsFile`, and `allFiles`.
## References
#5915 - mini-spec
## PR Checklist
* [x] Closes #2557
* [x] Tests added/passed
## Detailed Description of the Pull Request / Additional comments
Implemented as discussed in the attached spec. A new enum will be added for the SettingsUI when it becomes available.
## Validation Steps Performed
Added the following to my settings.json:
```json
{ "command": "openSettings", "keys":... },
{ "command": { "action": "openSettings" }, "keys":... },
{ "command": { "action": "openSettings", "target": "settingsFile" }, "keys":... },
{ "command": { "action": "openSettings", "target": "defaultsFile" }, "keys":... },
{ "command": { "action": "openSettings", "target": "allFiles" }, "keys":... }
```
2020-06-12 23:19:18 +02:00
|
|
|
{
|
2020-12-11 22:34:57 +01:00
|
|
|
case SettingsTarget::DefaultsFile:
|
|
|
|
openFile(CascadiaSettings::DefaultSettingsPath());
|
|
|
|
break;
|
|
|
|
case SettingsTarget::SettingsFile:
|
|
|
|
openFile(CascadiaSettings::SettingsPath());
|
|
|
|
break;
|
|
|
|
case SettingsTarget::AllFiles:
|
|
|
|
openFile(CascadiaSettings::DefaultSettingsPath());
|
|
|
|
openFile(CascadiaSettings::SettingsPath());
|
|
|
|
break;
|
Add keybinding arg to openSettings (#6299)
## Summary of the Pull Request
Adds the `target` keybinding arg to `openSettings`. Possible values include: `defaultsFile`, `settingsFile`, and `allFiles`.
## References
#5915 - mini-spec
## PR Checklist
* [x] Closes #2557
* [x] Tests added/passed
## Detailed Description of the Pull Request / Additional comments
Implemented as discussed in the attached spec. A new enum will be added for the SettingsUI when it becomes available.
## Validation Steps Performed
Added the following to my settings.json:
```json
{ "command": "openSettings", "keys":... },
{ "command": { "action": "openSettings" }, "keys":... },
{ "command": { "action": "openSettings", "target": "settingsFile" }, "keys":... },
{ "command": { "action": "openSettings", "target": "defaultsFile" }, "keys":... },
{ "command": { "action": "openSettings", "target": "allFiles" }, "keys":... }
```
2020-06-12 23:19:18 +02:00
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
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
|
|
|
// - Responds to changes in the TabView's item list by changing the
|
|
|
|
// tabview's visibility.
|
|
|
|
// - This method is also invoked when tabs are dragged / dropped as part of
|
|
|
|
// tab reordering and this method hands that case as well in concert with
|
|
|
|
// TabDragStarting and TabDragCompleted handlers that are set up in
|
|
|
|
// TerminalPage::Create()
|
2019-09-04 23:34:06 +02:00
|
|
|
// Arguments:
|
|
|
|
// - sender: the control that originated this event
|
|
|
|
// - eventArgs: the event's constituent arguments
|
2019-11-08 18:27:20 +01:00
|
|
|
void TerminalPage::_OnTabItemsChanged(const IInspectable& /*sender*/, const Windows::Foundation::Collections::IVectorChangedEventArgs& eventArgs)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2019-11-08 18:27:20 +01:00
|
|
|
if (_rearranging)
|
|
|
|
{
|
|
|
|
if (eventArgs.CollectionChange() == Windows::Foundation::Collections::CollectionChange::ItemRemoved)
|
|
|
|
{
|
|
|
|
_rearrangeFrom = eventArgs.Index();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eventArgs.CollectionChange() == Windows::Foundation::Collections::CollectionChange::ItemInserted)
|
|
|
|
{
|
|
|
|
_rearrangeTo = eventArgs.Index();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-09 23:01:08 +01:00
|
|
|
CommandPalette().Visibility(Visibility::Collapsed);
|
2019-09-04 23:34:06 +02:00
|
|
|
_UpdateTabView();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Additional responses to clicking on a TabView's item. Currently, just remove tab with middle click
|
|
|
|
// Arguments:
|
|
|
|
// - sender: the control that originated this event (TabViewItem)
|
|
|
|
// - eventArgs: the event's constituent arguments
|
|
|
|
void TerminalPage::_OnTabClick(const IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& eventArgs)
|
|
|
|
{
|
|
|
|
if (eventArgs.GetCurrentPoint(*this).Properties().IsMiddleButtonPressed())
|
|
|
|
{
|
2019-10-15 07:41:43 +02:00
|
|
|
_RemoveTabViewItem(sender.as<MUX::Controls::TabViewItem>());
|
2019-09-04 23:34:06 +02:00
|
|
|
eventArgs.Handled(true);
|
|
|
|
}
|
2020-05-04 22:57:12 +02:00
|
|
|
else if (eventArgs.GetCurrentPoint(*this).Properties().IsRightButtonPressed())
|
|
|
|
{
|
|
|
|
eventArgs.Handled(true);
|
|
|
|
}
|
2019-09-04 23:34:06 +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
|
|
|
void TerminalPage::_UpdatedSelectedTab(const int32_t index)
|
|
|
|
{
|
|
|
|
// Unfocus all the tabs.
|
|
|
|
for (auto tab : _tabs)
|
|
|
|
{
|
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::Unfocused);
|
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 (index >= 0)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
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 tab{ _tabs.GetAt(index) };
|
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
|
|
|
|
|
|
|
_tabContent.Children().Clear();
|
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
|
|
|
_tabContent.Children().Append(tab.Content());
|
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
|
|
|
|
2020-10-08 00:49:10 +02:00
|
|
|
// GH#7409: If the tab switcher is open, then we _don't_ want to
|
|
|
|
// automatically focus the new tab here. The tab switcher wants
|
|
|
|
// to be able to "preview" the selected tab as the user tabs
|
|
|
|
// through the menu, but if we toss the focus to the control
|
|
|
|
// here, then the user won't be able to navigate the ATS any
|
|
|
|
// longer.
|
|
|
|
//
|
2021-01-08 00:09:16 +01:00
|
|
|
// When the tab switcher is eventually dismissed, the focus will
|
2020-10-08 00:49:10 +02:00
|
|
|
// get tossed back to the focused terminal control, so we don't
|
|
|
|
// need to worry about focus getting lost.
|
|
|
|
if (CommandPalette().Visibility() != Visibility::Visible)
|
|
|
|
{
|
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);
|
2020-10-21 21:37:28 +02:00
|
|
|
_UpdateMRUTab(index);
|
2020-10-08 00:49:10 +02:00
|
|
|
}
|
2020-05-04 22:57:12 +02:00
|
|
|
|
2021-01-20 18:37:47 +01:00
|
|
|
tab.TabViewItem().StartBringIntoView();
|
|
|
|
|
2020-05-04 22:57:12 +02:00
|
|
|
// Raise an event that our title changed
|
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
|
|
|
_titleChangeHandlers(*this, tab.Title());
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Responds to the TabView control's Selection Changed event (to move a
|
2019-11-08 18:27:20 +01:00
|
|
|
// new terminal control into focus) when not in in the middle of a tab rearrangement.
|
2019-09-04 23:34:06 +02:00
|
|
|
// Arguments:
|
|
|
|
// - sender: the control that originated this event
|
|
|
|
// - eventArgs: the event's constituent arguments
|
2019-11-05 23:29:11 +01:00
|
|
|
void TerminalPage::_OnTabSelectionChanged(const IInspectable& sender, const WUX::Controls::SelectionChangedEventArgs& /*eventArgs*/)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-12-18 11:11:25 +01:00
|
|
|
if (!_rearranging && !_removing)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2019-11-08 18:27:20 +01:00
|
|
|
auto tabView = sender.as<MUX::Controls::TabView>();
|
|
|
|
auto selectedIndex = tabView.SelectedIndex();
|
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
|
|
|
_UpdatedSelectedTab(selectedIndex);
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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();
|
2020-02-04 22:51:11 +01:00
|
|
|
for (auto tab : _tabs)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
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 = _GetTerminalTabImpl(tab))
|
|
|
|
{
|
|
|
|
terminalTab->ResizeContent(newSize);
|
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2019-11-05 23:29:11 +01:00
|
|
|
void TerminalPage::_OnTabCloseRequested(const IInspectable& /*sender*/, const MUX::Controls::TabViewTabCloseRequestedEventArgs& eventArgs)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2019-10-15 07:41:43 +02:00
|
|
|
const auto tabViewItem = eventArgs.Tab();
|
2019-09-04 23:34:06 +02:00
|
|
|
_RemoveTabViewItem(tabViewItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
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::_RefreshUIForSettingsReload()
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
|
|
|
// Re-wire the keybindings to their handlers, as we'll have created a
|
|
|
|
// new AppKeyBindings object.
|
2020-09-14 22:38:56 +02:00
|
|
|
_HookupKeyBindings(_settings.KeyMap());
|
2019-09-04 23:34:06 +02:00
|
|
|
|
|
|
|
// Refresh UI elements
|
2020-10-28 17:22:26 +01:00
|
|
|
auto profiles = _settings.ActiveProfiles();
|
2020-09-09 22:49:53 +02:00
|
|
|
for (const auto& profile : profiles)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-08-28 03:09:22 +02:00
|
|
|
const auto profileGuid = profile.Guid();
|
2019-09-04 23:34:06 +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
|
|
|
try
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
2020-09-14 22:38:56 +02:00
|
|
|
// This can throw an exception if the profileGuid does
|
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
|
|
|
// not belong to an actual profile in the list of profiles.
|
2020-09-14 22:38:56 +02:00
|
|
|
auto settings{ winrt::make<TerminalSettings>(_settings, profileGuid, *_bindings) };
|
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
|
|
|
|
|
|
|
for (auto tab : _tabs)
|
|
|
|
{
|
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 = _GetTerminalTabImpl(tab))
|
|
|
|
{
|
|
|
|
terminalTab->UpdateSettings(settings, profileGuid);
|
|
|
|
}
|
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
|
|
|
}
|
2019-09-04 23:34:06 +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();
|
2019-09-04 23:34:06 +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
|
|
|
// 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.
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// Update the icon of the tab for the currently focused profile in that 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
|
|
|
// 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.
|
2020-02-04 22:51:11 +01:00
|
|
|
for (auto tab : _tabs)
|
2019-09-04 23:34:06 +02:00
|
|
|
{
|
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 = _GetTerminalTabImpl(tab))
|
|
|
|
{
|
|
|
|
_UpdateTabIcon(*terminalTab);
|
|
|
|
|
|
|
|
// Force the TerminalTab to re-grab its currently active control's title.
|
|
|
|
terminalTab->UpdateTitle();
|
|
|
|
}
|
2020-12-11 22:34:57 +01:00
|
|
|
else if (auto settingsTab = tab.try_as<TerminalApp::SettingsTab>())
|
|
|
|
{
|
|
|
|
settingsTab.UpdateSettings(_settings);
|
|
|
|
}
|
2021-01-19 12:44:04 +01:00
|
|
|
|
|
|
|
auto tabImpl{ winrt::get_self<TabBase>(tab) };
|
|
|
|
tabImpl->SetKeyMap(_settings.KeyMap());
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
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 weakThis{ get_weak() };
|
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());
|
|
|
|
|
|
|
|
// repopulate the new tab button's flyout with entries for each
|
|
|
|
// profile, which might have changed
|
|
|
|
if (auto page{ weakThis.get() })
|
|
|
|
{
|
|
|
|
_UpdateTabWidthMode();
|
|
|
|
_CreateNewTabFlyout();
|
|
|
|
}
|
2020-07-14 23:02:18 +02:00
|
|
|
|
|
|
|
// 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.
|
2020-09-09 22:49:53 +02:00
|
|
|
_isAlwaysOnTop = _settings.GlobalSettings().AlwaysOnTop();
|
2020-07-14 23:02:18 +02:00
|
|
|
_alwaysOnTopChangedHandlers(*this, nullptr);
|
2020-10-10 01:06:40 +02:00
|
|
|
|
|
|
|
// 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());
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
2020-08-19 19:33:19 +02:00
|
|
|
// This is a helper to aid in sorting commands by their `Name`s, alphabetically.
|
2020-10-06 18:56:59 +02:00
|
|
|
static bool _compareSchemeNames(const ColorScheme& lhs, const ColorScheme& rhs)
|
2020-08-19 19:33:19 +02:00
|
|
|
{
|
|
|
|
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>
|
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
|
|
|
{
|
2021-02-02 07:50:31 +01:00
|
|
|
IVector<SettingsLoadWarnings> warnings{ winrt::single_threaded_vector<SettingsLoadWarnings>() };
|
2020-08-19 19:33:19 +02:00
|
|
|
|
2020-10-06 18:56:59 +02:00
|
|
|
std::vector<ColorScheme> sortedSchemes;
|
2020-08-28 05:49:16 +02:00
|
|
|
sortedSchemes.reserve(schemes.Size());
|
2020-08-19 19:33:19 +02:00
|
|
|
|
|
|
|
for (const auto& nameAndScheme : schemes)
|
|
|
|
{
|
2020-08-28 05:49:16 +02:00
|
|
|
sortedSchemes.push_back(nameAndScheme.Value());
|
2020-08-19 19:33:19 +02:00
|
|
|
}
|
|
|
|
std::sort(sortedSchemes.begin(),
|
|
|
|
sortedSchemes.end(),
|
|
|
|
_compareSchemeNames);
|
|
|
|
|
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,
|
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()
|
|
|
|
{
|
2020-10-06 18:56:59 +02:00
|
|
|
IMap<winrt::hstring, Command> copyOfCommands = _ExpandCommands(_settings.GlobalSettings().Commands(),
|
2020-10-28 17:22:26 +01:00
|
|
|
_settings.ActiveProfiles().GetView(),
|
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
|
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);
|
|
|
|
}
|
|
|
|
|
2020-01-27 16:34:12 +01:00
|
|
|
// Method Description:
|
2020-06-01 23:57:30 +02:00
|
|
|
// - Sets the initial actions to process on startup. We'll make a copy of
|
|
|
|
// this list, and process these actions when we're loaded.
|
2020-01-27 16:34:12 +01:00
|
|
|
// - This function will have no effective result after Create() is called.
|
|
|
|
// Arguments:
|
2020-06-01 23:57:30 +02:00
|
|
|
// - actions: a list of Actions to process on startup.
|
2020-01-27 16:34:12 +01:00
|
|
|
// Return Value:
|
2020-06-01 23:57:30 +02:00
|
|
|
// - <none>
|
2020-10-06 18:56:59 +02:00
|
|
|
void TerminalPage::SetStartupActions(std::vector<ActionAndArgs>& actions)
|
2020-01-27 16:34:12 +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
|
|
|
// 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;
|
2020-10-06 18:56:59 +02:00
|
|
|
_startupActions = winrt::single_threaded_vector<ActionAndArgs>(std::move(listCopy));
|
2020-01-27 16:34:12 +01:00
|
|
|
}
|
|
|
|
|
2020-07-01 21:43:28 +02:00
|
|
|
winrt::TerminalApp::IDialogPresenter TerminalPage::DialogPresenter() const
|
|
|
|
{
|
|
|
|
return _dialogPresenter.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TerminalPage::DialogPresenter(winrt::TerminalApp::IDialogPresenter dialogPresenter)
|
|
|
|
{
|
|
|
|
_dialogPresenter = dialogPresenter;
|
|
|
|
}
|
|
|
|
|
2020-11-18 23:24:11 +01:00
|
|
|
// Method Description:
|
|
|
|
// - Gets the taskbar state value from the last active control
|
|
|
|
// Return Value:
|
|
|
|
// - The taskbar state of the last active control
|
|
|
|
size_t TerminalPage::GetLastActiveControlTaskbarState()
|
|
|
|
{
|
|
|
|
if (auto control{ _GetActiveControl() })
|
|
|
|
{
|
|
|
|
return gsl::narrow_cast<size_t>(control.TaskbarState());
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Gets the taskbar progress value from the last active control
|
|
|
|
// Return Value:
|
|
|
|
// - The taskbar progress of the last active control
|
|
|
|
size_t TerminalPage::GetLastActiveControlTaskbarProgress()
|
|
|
|
{
|
|
|
|
if (auto control{ _GetActiveControl() })
|
|
|
|
{
|
|
|
|
return gsl::narrow_cast<size_t>(control.TaskbarProgress());
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// 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();
|
|
|
|
}
|
2020-10-27 03:24:54 +01:00
|
|
|
|
|
|
|
for (const auto& tab : _tabs)
|
|
|
|
{
|
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.TabViewItem().ContextFlyout())
|
2020-10-27 03:24:54 +01:00
|
|
|
{
|
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.TabViewItem().ContextFlyout().Hide();
|
2020-10-27 03:24:54 +01:00
|
|
|
}
|
|
|
|
}
|
2019-09-04 23:34:06 +02:00
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
const auto termControl = _GetActiveControl();
|
|
|
|
termControl.CreateSearchBoxControl();
|
|
|
|
}
|
|
|
|
|
2020-07-13 19:40:20 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Toggles borderless mode. Hides the tab row, and raises our
|
2020-07-14 23:02:18 +02:00
|
|
|
// FocusModeChanged event.
|
2020-07-13 19:40:20 +02:00
|
|
|
// Arguments:
|
|
|
|
// - <none>
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void TerminalPage::ToggleFocusMode()
|
|
|
|
{
|
|
|
|
_isInFocusMode = !_isInFocusMode;
|
|
|
|
_UpdateTabView();
|
2020-07-14 23:02:18 +02:00
|
|
|
_focusModeChangedHandlers(*this, nullptr);
|
2020-07-13 19:40:20 +02:00
|
|
|
}
|
|
|
|
|
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
|
2020-07-14 23:02:18 +02:00
|
|
|
// 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>
|
2020-06-01 23:57:30 +02:00
|
|
|
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();
|
2020-07-14 23:02:18 +02:00
|
|
|
_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
|
|
|
}
|
|
|
|
|
2020-05-04 22:57:12 +02: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;
|
|
|
|
|
2020-05-05 22:33:07 +02:00
|
|
|
// 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
|
2020-05-04 22:57:12 +02:00
|
|
|
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.
|
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
|
|
|
{
|
2020-12-16 03:03:13 +01: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
|
|
|
{
|
2020-12-16 03:03:13 +01: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 {};
|
|
|
|
}
|
|
|
|
|
2020-06-26 22:38:02 +02:00
|
|
|
void TerminalPage::_CommandPaletteClosed(const IInspectable& /*sender*/,
|
|
|
|
const RoutedEventArgs& /*eventArgs*/)
|
|
|
|
{
|
2020-12-09 23:01:08 +01:00
|
|
|
// We don't want to set focus on the tab if fly-out is open as it will be closed
|
|
|
|
// TODO GH#5400: consider checking we are not in the opening state, by hooking both Opening and Open events
|
|
|
|
if (!_newTabButton.Flyout().IsOpen())
|
2020-06-26 22:38:02 +02:00
|
|
|
{
|
2020-12-09 23:01:08 +01:00
|
|
|
// Return focus to the active control
|
|
|
|
if (auto index{ _GetFocusedTabIndex() })
|
|
|
|
{
|
|
|
|
_tabs.GetAt(*index).Focus(FocusState::Programmatic);
|
|
|
|
_UpdateMRUTab(index.value());
|
|
|
|
}
|
2020-06-26 22:38:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-14 23:02:18 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-09-18 02:13:11 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Updates all tabs with their current index in _tabs.
|
|
|
|
// Arguments:
|
|
|
|
// - <none>
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void TerminalPage::_UpdateTabIndices()
|
|
|
|
{
|
2020-10-15 13:40:44 +02:00
|
|
|
const uint32_t size = _tabs.Size();
|
|
|
|
for (uint32_t i = 0; i < size; ++i)
|
2020-09-18 02:13:11 +02:00
|
|
|
{
|
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 tab{ _tabs.GetAt(i) };
|
|
|
|
auto tabImpl{ winrt::get_self<TabBase>(tab) };
|
|
|
|
tabImpl->UpdateTabViewIndex(i, size);
|
2020-09-18 02:13:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-11 22:34:57 +01:00
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
|
2021-01-25 23:52:12 +01:00
|
|
|
sui.PreviewKeyDown({ this, &TerminalPage::_SUIPreviewKeyDownHandler });
|
|
|
|
|
2020-12-11 22:34:57 +01:00
|
|
|
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);
|
2021-01-19 12:44:04 +01:00
|
|
|
newTabImpl->SetKeyMap(_settings.KeyMap());
|
2020-12-11 22:34:57 +01:00
|
|
|
|
|
|
|
// 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 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
|
2021-01-04 20:32:53 +01:00
|
|
|
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:
|
2020-10-27 02:19:52 +01:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2020-10-21 21:37:28 +02:00
|
|
|
// Method Description:
|
|
|
|
// - Bumps the tab in its in-order index up to the top of the mru list.
|
|
|
|
// Arguments:
|
|
|
|
// - index: the in-order index of the tab to bump.
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void TerminalPage::_UpdateMRUTab(const uint32_t index)
|
|
|
|
{
|
|
|
|
uint32_t mruIndex;
|
2020-12-10 01:36:28 +01:00
|
|
|
const auto tab = _tabs.GetAt(index);
|
|
|
|
if (_mruTabs.IndexOf(tab, mruIndex))
|
2020-10-21 21:37:28 +02:00
|
|
|
{
|
|
|
|
if (mruIndex > 0)
|
|
|
|
{
|
2020-12-10 01:36:28 +01:00
|
|
|
_mruTabs.RemoveAt(mruIndex);
|
|
|
|
_mruTabs.InsertAt(0, tab);
|
2020-10-21 21:37:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-25 23:09:27 +01:00
|
|
|
// Method Description:
|
|
|
|
// - Moves the tab to another index in the tabs row (if required).
|
|
|
|
// Arguments:
|
|
|
|
// - currentTabIndex: the current index of the tab to move
|
|
|
|
// - suggestedNewTabIndex: the new index of the tab, might get clamped to fit int the tabs row boundaries
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void TerminalPage::_TryMoveTab(const uint32_t currentTabIndex, const int32_t suggestedNewTabIndex)
|
|
|
|
{
|
|
|
|
auto newTabIndex = gsl::narrow_cast<uint32_t>(std::clamp<int32_t>(suggestedNewTabIndex, 0, _tabs.Size() - 1));
|
|
|
|
if (currentTabIndex != newTabIndex)
|
|
|
|
{
|
|
|
|
auto tab = _tabs.GetAt(currentTabIndex);
|
|
|
|
auto tabViewItem = tab.TabViewItem();
|
|
|
|
_tabs.RemoveAt(currentTabIndex);
|
|
|
|
_tabs.InsertAt(newTabIndex, tab);
|
|
|
|
_UpdateTabIndices();
|
|
|
|
|
|
|
|
_tabView.TabItems().RemoveAt(currentTabIndex);
|
|
|
|
_tabView.TabItems().InsertAt(newTabIndex, tabViewItem);
|
|
|
|
_tabView.SelectedItem(tabViewItem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-04 22:44:53 +01:00
|
|
|
// Method Description:
|
|
|
|
// - Displays a dialog stating the "Touch Keyboard and Handwriting Panel
|
|
|
|
// Service" is disabled.
|
|
|
|
void TerminalPage::ShowKeyboardServiceWarning()
|
|
|
|
{
|
2020-12-14 18:37:33 +01:00
|
|
|
if (auto keyboardWarningInfoBar = FindName(L"KeyboardWarningInfoBar").try_as<MUX::Controls::InfoBar>())
|
2020-11-04 22:44:53 +01:00
|
|
|
{
|
2020-12-14 18:37:33 +01:00
|
|
|
keyboardWarningInfoBar.IsOpen(true);
|
2020-11-04 22:44:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2020-12-14 18:37:33 +01:00
|
|
|
// "KeyboardServiceDisabled" InfoBar. This InfoBar is used to warn the user
|
2020-11-04 22:44:53 +01:00
|
|
|
// if the keyboard service is disabled, and uses the OS localization for
|
2020-12-14 18:37:33 +01:00
|
|
|
// the service's actual name. It's bound to the bar in XAML.
|
2020-11-04 22:44:53 +01:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2021-01-21 02:17:59 +01:00
|
|
|
// Method Description:
|
|
|
|
// - Hides cursor if required
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void TerminalPage::_HidePointerCursorHandler(const IInspectable& /*sender*/, const IInspectable& /*eventArgs*/)
|
|
|
|
{
|
|
|
|
if (_shouldMouseVanish && !_isMouseHidden)
|
|
|
|
{
|
|
|
|
CoreWindow::GetForCurrentThread().PointerCursor(nullptr);
|
|
|
|
_isMouseHidden = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method Description:
|
|
|
|
// - Restores cursor if required
|
|
|
|
// Return Value:
|
|
|
|
// - <none>
|
|
|
|
void TerminalPage::_RestorePointerCursorHandler(const IInspectable& /*sender*/, const IInspectable& /*eventArgs*/)
|
|
|
|
{
|
|
|
|
if (_isMouseHidden)
|
|
|
|
{
|
|
|
|
CoreWindow::GetForCurrentThread().PointerCursor(_defaultPointerCursor);
|
|
|
|
_isMouseHidden = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:34:06 +02:00
|
|
|
// -------------------------------- WinRT Events ---------------------------------
|
|
|
|
// Winrt events need a method for adding a callback to the event and removing the callback.
|
|
|
|
// These macros will define them both for you.
|
|
|
|
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, TitleChanged, _titleChangeHandlers, winrt::Windows::Foundation::IInspectable, winrt::hstring);
|
|
|
|
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, LastTabClosed, _lastTabClosedHandlers, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::LastTabClosedEventArgs);
|
|
|
|
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, SetTitleBarContent, _setTitleBarContentHandlers, winrt::Windows::Foundation::IInspectable, UIElement);
|
2020-07-14 23:02:18 +02:00
|
|
|
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, FocusModeChanged, _focusModeChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
|
|
|
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, FullscreenChanged, _fullscreenChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
|
|
|
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, AlwaysOnTopChanged, _alwaysOnTopChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
2020-11-18 23:55:10 +01:00
|
|
|
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, RaiseVisualBell, _raiseVisualBellHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
2020-11-18 23:24:11 +01:00
|
|
|
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, SetTaskbarProgress, _setTaskbarProgressHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
2019-07-09 23:47:30 +02:00
|
|
|
}
|