2020-10-06 09:56:59 -07:00
<?xml version="1.0" encoding="utf-8"?>
<root>
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
<!--
Microsoft ResX Schema
2020-10-06 09:56:59 -07:00
Version 2.0
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
2020-10-06 09:56:59 -07:00
associated with the data types.
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
2020-10-06 09:56:59 -07:00
Example:
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
2020-10-06 09:56:59 -07:00
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
There are any number of "resheader" rows that contain simple
2020-10-06 09:56:59 -07:00
name/value pairs.
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
2020-10-06 09:56:59 -07:00
mimetype set.
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
2020-10-06 09:56:59 -07:00
extensible. For a given mimetype the value must be set accordingly:
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
2020-10-06 09:56:59 -07:00
read any of the formats listed below.
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
2020-10-06 09:56:59 -07:00
mimetype: application/x-microsoft.net.object.binary.base64
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
value : The object must be serialized with
2020-10-06 09:56:59 -07:00
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
2020-10-06 09:56:59 -07:00
mimetype: application/x-microsoft.net.object.soap.base64
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
value : The object must be serialized with
2020-10-06 09:56:59 -07:00
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
value : The object must be serialized into a byte array
2020-10-06 09:56:59 -07:00
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="SetColorSchemeParentCommandName" xml:space="preserve">
2024-08-21 11:13:39 -07:00
<value>Select color scheme...</value>
2020-10-06 09:56:59 -07:00
</data>
<data name="NewTabParentCommandName" xml:space="preserve">
2024-08-21 11:13:39 -07:00
<value>New tab...</value>
2020-10-06 09:56:59 -07:00
</data>
<data name="SplitPaneParentCommandName" xml:space="preserve">
2024-08-21 11:13:39 -07:00
<value>Split pane...</value>
2020-10-06 09:56:59 -07:00
</data>
Add a snippets pane (#17330)
This adds a snippets pane, which can be a static pane with all your
snippets (`sendInput` actions) in it. (See #17329)
This pane has a treeview with these actions in it, that we can filter
with a textbox at the top.
Play buttons next to entries make it quick to run the command you found.
Bound in the default actions with
```json
{ "command": { "action": "splitPane", "type": "snippets" }, "id": "Terminal.OpenSnippetsPane", "name": { "key": "SnippetsPaneCommandName" } },
```
re: #1595
----
TODO, from 06-04 bug bash
* [x] Snippets pane doesn't display some "no snippets found" text if
there aren't any yet
* [x] open snippets pane; find a "send input"; click the play button on
it; input is sent to active pane; begin typing
* [x] I can open an infinite amount of suggestions panes
* ~I'm closing this as by-design for now at least. Nothing stopping
anyone from opening infinite of any kind of pane.~
* ~This would require kind of a lot of refactoring in this PR to mark a
kind of pane as being a singleton or singleton-per-tab~
* Okay everyone hates infinite suggestions panes, so I got rid of that
* [x] Ctrl+Shift+W should still work in the snippets pane even if focus
isn't in textbox
* [ ] open snippets pane; click on text box; press TAB key;
* [ ] If you press TAB again, I have no idea where focus went
* [x] some previews don't work. Like `^c` (`"input": "\u0003"`)
* [x] nested items just give you a bit of extra space for no reason and
it looks a little awkward
* [x] UI Suggestion: add padding on the right side
* [ ] [Accessibility] Narrator says "Clear buffer; Suggestions found
132" when you open the snippets pane
- Note: this is probably Narrator reading out the command palette (since
that's where I opened it from)
- We should probably expect something like "Snippets", then (assuming
focus is thrown into text box) "Type to filter snippets" or something
like that
2024-07-08 13:26:07 -05:00
<data name="SnippetsPaneCommandName" xml:space="preserve">
<value>Open snippets pane</value>
<comment>This will open a pane with a list of the users's saved commands ("snippets") in it</comment>
</data>
2023-03-31 17:12:00 -05:00
<data name="ApplicationDisplayNamePortable" xml:space="preserve">
<value>Terminal (Portable)</value>
<comment>This display name is used when the Terminal application is running in a "portable" mode, where settings are not stored in a shared location.</comment>
</data>
2020-10-06 09:56:59 -07:00
<data name="ApplicationDisplayNameUnpackaged" xml:space="preserve">
2022-01-27 17:34:06 -06:00
<value>Terminal (Unpackaged)</value>
2020-10-06 09:56:59 -07:00
<comment>This display name is used when the application's name cannot be determined</comment>
</data>
<data name="ApplicationVersionUnknown" xml:space="preserve">
<value>Unknown</value>
<comment>This is displayed when the version of the application cannot be determined</comment>
</data>
<data name="AdjustFontSizeCommandKey" xml:space="preserve">
<value>Adjust font size</value>
</data>
<data name="CloseOtherTabsCommandKey" xml:space="preserve">
<value>Close tabs other than index {0}</value>
<comment>{0} will be replaced with a number</comment>
</data>
<data name="CloseOtherTabsDefaultCommandKey" xml:space="preserve">
<value>Close all other tabs</value>
</data>
<data name="ClosePaneCommandKey" xml:space="preserve">
<value>Close pane</value>
</data>
2021-06-25 20:22:52 +01:00
<data name="CloseTabAtIndexCommandKey" xml:space="preserve">
<value>Close tab at index {0}</value>
<comment>{0} will be replaced with a number</comment>
</data>
2020-10-06 09:56:59 -07:00
<data name="CloseTabCommandKey" xml:space="preserve">
<value>Close tab</value>
</data>
<data name="CloseTabsAfterCommandKey" xml:space="preserve">
<value>Close tabs after index {0}</value>
<comment>{0} will be replaced with a number</comment>
</data>
2021-05-04 21:15:25 -07:00
<data name="CopySuffix" xml:space="preserve">
<value>Copy</value>
<comment>The suffix we add to the name of a duplicated profile.</comment>
</data>
2020-11-26 00:09:27 +02:00
<data name="MoveTabCommandKey" xml:space="preserve">
<value>Move tab {0}</value>
2026-01-13 00:54:57 +05:30
<comment>{0} will be replaced with a "forward (right)" / "backward (left)"</comment>
2020-11-26 00:09:27 +02:00
</data>
Add support for moving panes and tabs between windows (#14866)
_Lo! Harken to me, for I shall divulge the heart of the tab tear-out
saga. Verily, this PR shall bestow upon thee the power to move tabs and
panes between windows by means of pre-defined actions. Though be warned,
it does not yet grant thee the power to drag and drop them as thou
mayest desire. Yet, the same plumbing that underpins this work shall
remain steadfast. Behold, the majority of this undertaking concerns the
elevation of the RequestMoveContent event from the TerminalPage to the
very summit of the Monarch. From thence, a great AttachContent method
shall descend back to the lowest depths. Furthermore, there are minor
revisions to TermControl that shall enable thee to better detach the
content and attach it to a new one._
This is the most important part of the tab tear-out saga. This PR
enables the user to move tabs and panes between windows using
pre-defined actions. It does _not_ enable the user to drag/drop them
yet, but the same fundamental plumbing will still apply. Most of the PR
is plumbing the `RequestMoveContent` event up from the `TerminalPage` up
to the `Monarch`, and then plumbing an `AttachContent` method back down.
There are also small changes to `TermControl` to better support
detaching the content and attaching to a new one.
For testing, I recommend:
```json
{ "keys": "f1", "command": { "action": "moveTab", "window": "1" } },
{ "keys": "f2", "command": { "action": "moveTab", "window": "2" } },
{ "keys": "f3", "command": { "action": "movePane", "window": "1" } },
{ "keys": "f4", "command": { "action": "movePane", "window": "2" } },
{ "keys": "shift+f3", "command": { "action": "movePane", "window": "1", "index": 3 } },
{ "keys": "shift+f4", "command": { "action": "movePane", "window": "2", "index": 3 } },
```
* Related to #1256
* Related to #5000
---------
Co-authored-by: Carlos Zamora <carlos.zamora@microsoft.com>
2023-03-30 09:37:53 -05:00
<data name="MoveTabToWindowCommandKey" xml:space="preserve">
<value>Move tab to window "{0}"</value>
<comment>{0} will be replaced with a user-specified name of a window</comment>
</data>
2023-05-01 10:20:23 -05:00
<data name="MoveTabToNewWindowCommandKey" xml:space="preserve">
<value>Move tab to a new window</value>
</data>
2020-11-26 00:09:27 +02:00
<data name="MoveTabDirectionForward" xml:space="preserve">
2026-01-13 00:54:57 +05:30
<value>forward (right)</value>
2020-11-26 00:09:27 +02:00
</data>
<data name="MoveTabDirectionBackward" xml:space="preserve">
2026-01-13 00:54:57 +05:30
<value>backward (left)</value>
2020-11-26 00:09:27 +02:00
</data>
2020-10-06 09:56:59 -07:00
<data name="CloseTabsAfterDefaultCommandKey" xml:space="preserve">
<value>Close all tabs after the current tab</value>
</data>
<data name="CloseWindowCommandKey" xml:space="preserve">
<value>Close window</value>
</data>
2021-09-10 11:25:43 -07:00
<data name="OpenSystemMenuCommandKey" xml:space="preserve">
<value>Open system menu</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="CommandPromptDisplayName" xml:space="preserve">
<value>Command Prompt</value>
<comment>This is the name of "Command Prompt", as localized in Windows. The localization here should match the one in the Windows product for "Command Prompt"</comment>
</data>
<data name="CopyTextAsSingleLineCommandKey" xml:space="preserve">
<value>Copy text as a single line</value>
</data>
<data name="CopyTextCommandKey" xml:space="preserve">
<value>Copy text</value>
</data>
<data name="DecreaseFontSizeCommandKey" xml:space="preserve">
<value>Decrease font size</value>
</data>
<data name="DecreaseFontSizeWithAmountCommandKey" xml:space="preserve">
<value>Decrease font size, amount: {0}</value>
<comment>{0} will be replaced with a positive number</comment>
</data>
<data name="DirectionDown" xml:space="preserve">
<value>down</value>
</data>
<data name="DirectionLeft" xml:space="preserve">
<value>left</value>
</data>
<data name="DirectionRight" xml:space="preserve">
<value>right</value>
</data>
<data name="DirectionUp" xml:space="preserve">
<value>up</value>
</data>
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 10:36:05 -08:00
<data name="DirectionPrevious" xml:space="preserve">
<value>previous</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="DuplicatePaneCommandKey" xml:space="preserve">
<value>Duplicate pane</value>
</data>
<data name="DuplicateTabCommandKey" xml:space="preserve">
<value>Duplicate tab</value>
</data>
<data name="ExecuteCommandlineCommandKey" xml:space="preserve">
<value>Run commandline "{0}" in this window</value>
<comment>{0} will be replaced with a user-defined commandline</comment>
</data>
<data name="FindCommandKey" xml:space="preserve">
<value>Find</value>
</data>
Add `findNext`, `findPrev` actions (#8917)
This PR is a resurrection of #8522. @Hegunumo has apparently deleted
their account, but the contribution was still valuable. I'm just here to
get it across the finish line.
This PR adds new action for navigating to the next & previous search
results. These actions are unbound by default. These actions can be used
from directly within the search dialog also, to immediately navigate the
results.
Furthermore, if you have a search started, and close the search box,
then press this keybinding, _it will still perform the search_. So you
can just hit <kbd>F3</kbd> repeatedly with the dialog closed to keep
searching new results. Neat!
If you dispatch the action on the key down, then dismiss a selection on
a key up, we'll end up immediately destroying the selection when you
release the bound key. That's annoying. It also bothers @carlos-zamora
in #3758. However, I _think_ we can just only dismiss the selection on a
key up. I _think_ that's fine. It _seems_ fine so far. We've got an
entire release cycle to futz with it.
## Validation Steps Performed
I've played with it all day and it seems _crisp_.
Closes #7695
Co-authored-by: Kiminori Kaburagi <yukawa_hidenori@icloud.com>
2021-02-18 13:21:35 -06:00
<data name="FindNextCommandKey" xml:space="preserve">
<value>Find next search match</value>
</data>
<data name="FindPrevCommandKey" xml:space="preserve">
<value>Find previous search match</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="IncreaseFontSizeCommandKey" xml:space="preserve">
<value>Increase font size</value>
</data>
<data name="IncreaseFontSizeWithAmountCommandKey" xml:space="preserve">
<value>Increase font size, amount: {0}</value>
<comment>{0} will be replaced with a positive number</comment>
</data>
<data name="MoveFocusCommandKey" xml:space="preserve">
<value>Move focus</value>
</data>
<data name="MoveFocusWithArgCommandKey" xml:space="preserve">
<value>Move focus {0}</value>
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 10:36:05 -08:00
<comment>{0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", "DirectionDown"</comment>
</data>
<data name="MoveFocusToLastUsedPane" xml:space="preserve">
<value>Move focus to the last used pane</value>
2020-10-06 09:56:59 -07:00
</data>
2021-08-26 13:58:56 -04:00
<data name="MoveFocusNextInOrder" xml:space="preserve">
<value>Move focus to the next pane in order</value>
</data>
<data name="MoveFocusPreviousInOrder" xml:space="preserve">
<value>Move focus to the previous pane in order</value>
</data>
<data name="MoveFocusFirstPane" xml:space="preserve">
<value>Move focus to the first pane</value>
</data>
Add the ability to interact with subtrees of panes (#11153)
This commit adds the ability to interact with subtrees of panes.
Have you ever thought that you don't have enough regression testing to
do? Boy do I have the PR for you! This breaks all kinds of assumptions
about what is or is not focused, largely complicated by the fact that a
pane is not a proper control. I did my best to cover as many cases as I
could, but I wouldn't be surprised if there are some things broken that
I am unaware of.
Done:
- Add `parent` and `child` movement directions to move up and down the
tree respectively
- When a parent pane is selected it will have borders all around it in
addition to any borders the children have.
- Fix focus, swap, split, zoom, toggle orientation, resize, and move to
all handle interacting with more than one pane.
- Similarly the actions for font size changing, closing, read-only, clearing
buffer, and changing color scheme will distribute to all children.
- This technically leaves control focus on the original control in the
focused subtree because panes aren't proper controls themselves. This
is also used to make sure we go back down the same path with the
`child` movement.
- You can zoom a parent pane, and click between different zoomed
sub-panes and it won't unzoom you until you use moveFocus or another
action. This wasn't explicitly programmed behavior so it is probably
buggy (I've quashed a couple at least). It is a natural consequence of
showing multiple terminals and allowing you to focus a terminal and a
parent separately, since changing the active pane directly does not
unzoom. This also means there can be a disconnect between what pane is
zoomed and what pane is active.
## Validation Steps Performed
Tested focus movement, swapping, moving panes, and zooming.
Closes #10733
2021-09-28 15:16:05 -04:00
<data name="MoveFocusParentPane" xml:space="preserve">
<value>Move focus to the parent pane</value>
</data>
<data name="MoveFocusChildPane" xml:space="preserve">
<value>Move focus to the child pane</value>
</data>
Move Pane to Tab (GH7075) (#10780)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed.
This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
#4587
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #7075
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Things done:
- Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work.
- Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls.
- Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired.
- Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early).
- Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 .
To do:
- Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary.
Next Steps:
- In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI.
- Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab).
- Its been 10 years, I just really want to use concepts already.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 12:41:17 -04:00
<data name="SwapPaneCommandKey" xml:space="preserve">
<value>Swap pane</value>
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
This work potentially touches on: #1000 #2398 and #4922
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality)
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes.
Work currently done:
- Add boilerplate/infrastructure for argument parsing, hotkeys, event handling
- Adds the `MovePane` function that finds the focused pane, and then tries to find
a pane that is visually adjacent to according to direction.
- First pass at the `SwapPanes` function that swaps the tree location of two panes
- First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus`
that search the tree for the currently focused pane, and then climbs back up the tree
to try to find a sibling pane that is adjacent to it.
- An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction.
Next steps:
- Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function.
- Do we want default hotkeys for the new actions?
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 08:53:03 -04:00
</data>
Move Pane to Tab (GH7075) (#10780)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed.
This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
#4587
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #7075
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Things done:
- Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work.
- Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls.
- Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired.
- Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early).
- Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 .
To do:
- Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary.
Next Steps:
- In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI.
- Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab).
- Its been 10 years, I just really want to use concepts already.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 12:41:17 -04:00
<data name="SwapPaneWithArgCommandKey" xml:space="preserve">
<value>Swap pane {0}</value>
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
This work potentially touches on: #1000 #2398 and #4922
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality)
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes.
Work currently done:
- Add boilerplate/infrastructure for argument parsing, hotkeys, event handling
- Adds the `MovePane` function that finds the focused pane, and then tries to find
a pane that is visually adjacent to according to direction.
- First pass at the `SwapPanes` function that swaps the tree location of two panes
- First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus`
that search the tree for the currently focused pane, and then climbs back up the tree
to try to find a sibling pane that is adjacent to it.
- An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction.
Next steps:
- Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function.
- Do we want default hotkeys for the new actions?
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 08:53:03 -04:00
<comment>{0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", "DirectionDown"</comment>
</data>
Move Pane to Tab (GH7075) (#10780)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed.
This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
#4587
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #7075
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Things done:
- Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work.
- Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls.
- Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired.
- Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early).
- Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 .
To do:
- Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary.
Next Steps:
- In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI.
- Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab).
- Its been 10 years, I just really want to use concepts already.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 12:41:17 -04:00
<data name="SwapPaneToLastUsedPane" xml:space="preserve">
<value>Swap panes with the last used pane</value>
Preliminary work to add Swap Panes functionality (GH Issues 1000, 4922) (#10638)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to swap a pane with an adjacent (Up/Down/Left/Right) neighbor.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
This work potentially touches on: #1000 #2398 and #4922
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes a component of #1000 (partially, comment), #4922 (partially, `SwapPanes` function is added but not hooked up, no detach functionality)
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Its been a while since I've written C++ code, and it is my first time working on a Windows application. I hope that I have not made too many mistakes.
Work currently done:
- Add boilerplate/infrastructure for argument parsing, hotkeys, event handling
- Adds the `MovePane` function that finds the focused pane, and then tries to find
a pane that is visually adjacent to according to direction.
- First pass at the `SwapPanes` function that swaps the tree location of two panes
- First working version of helpers `_FindFocusAndNeighbor` and `_FindNeighborFromFocus`
that search the tree for the currently focused pane, and then climbs back up the tree
to try to find a sibling pane that is adjacent to it.
- An `_IsAdjacent' function that tests whether two panes, given their relative offsets, are adjacent to each other according to the direction.
Next steps:
- Once working these functions (`_FindFocusAndNeighbor`, etc) could be utilized to also solve #2398 by updating the `NavigateFocus` function.
- Do we want default hotkeys for the new actions?
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
At this point, compilation and manual testing of functionality (with hotkeys) by creating panes, adding distinguishers to each pane, and then swapping them around to confirm they went to the right location.
2021-07-22 08:53:03 -04:00
</data>
2021-08-26 13:58:56 -04:00
<data name="SwapPaneNextInOrder" xml:space="preserve">
<value>Swap panes with the next pane in order</value>
</data>
<data name="SwapPanePreviousInOrder" xml:space="preserve">
<value>Swap panes with the previous pane in order</value>
</data>
<data name="SwapPaneFirstPane" xml:space="preserve">
<value>Swap panes with the first pane</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="NewTabCommandKey" xml:space="preserve">
<value>New tab</value>
</data>
<data name="NewWindowCommandKey" xml:space="preserve">
<value>New window</value>
</data>
2021-03-30 11:08:03 -05:00
<data name="IdentifyWindowCommandKey" xml:space="preserve">
<value>Identify window</value>
</data>
<data name="IdentifyWindowsCommandKey" xml:space="preserve">
<value>Identify windows</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="NextTabCommandKey" xml:space="preserve">
<value>Next tab</value>
</data>
<data name="OpenBothSettingsFilesCommandKey" xml:space="preserve">
2022-06-10 11:41:13 -05:00
<value>Open both settings and default settings files (JSON)</value>
<comment>{Locked="JSON"}. "JSON" is the extension of the file that will be opened.</comment>
2020-10-06 09:56:59 -07:00
</data>
<data name="OpenDefaultSettingsCommandKey" xml:space="preserve">
2022-06-10 11:41:13 -05:00
<value>Open default settings file (JSON)</value>
<comment>{Locked="JSON"}. "JSON" is the extension of the file that will be opened.</comment>
2020-10-06 09:56:59 -07:00
</data>
<data name="OpenNewTabDropdownCommandKey" xml:space="preserve">
<value>Open new tab dropdown</value>
</data>
<data name="OpenSettingsCommandKey" xml:space="preserve">
2022-06-10 11:41:13 -05:00
<value>Open settings file (JSON)</value>
<comment>{Locked="JSON"}. "JSON" is the extension of the file that will be opened.</comment>
2020-10-06 09:56:59 -07:00
</data>
2024-12-05 04:20:13 -08:00
<data name="SettingsFileOpenInExplorerCommandKey" xml:space="preserve">
<value>Open the settings file directory</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="OpenTabColorPickerCommandKey" xml:space="preserve">
2024-08-21 11:13:39 -07:00
<value>Set tab color...</value>
2020-10-06 09:56:59 -07:00
</data>
<data name="PasteTextCommandKey" xml:space="preserve">
<value>Paste</value>
</data>
<data name="PrevTabCommandKey" xml:space="preserve">
<value>Previous tab</value>
</data>
<data name="RenameTabCommandKey" xml:space="preserve">
<value>Rename tab to "{0}"</value>
<comment>{0} will be replaced with a user-defined string</comment>
</data>
<data name="ResetFontSizeCommandKey" xml:space="preserve">
<value>Reset font size</value>
</data>
<data name="ResetTabColorCommandKey" xml:space="preserve">
<value>Reset tab color</value>
</data>
<data name="ResetTabNameCommandKey" xml:space="preserve">
<value>Reset tab title</value>
</data>
2020-10-29 05:36:30 +10:00
<data name="OpenTabRenamerCommandKey" xml:space="preserve">
2024-08-21 11:13:39 -07:00
<value>Rename tab</value>
2020-10-29 05:36:30 +10:00
</data>
2020-10-06 09:56:59 -07:00
<data name="ResizePaneCommandKey" xml:space="preserve">
<value>Resize pane</value>
</data>
<data name="ResizePaneWithArgCommandKey" xml:space="preserve">
<value>Resize pane {0}</value>
<comment>{0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", or "DirectionDown"</comment>
</data>
<data name="ScrollDownCommandKey" xml:space="preserve">
2020-10-27 03:19:52 +02:00
<value>Scroll down</value>
</data>
<data name="ScrollDownSeveralRowsCommandKey" xml:space="preserve">
<value>Scroll down {0} line(s)</value>
<comment>{0} will be replaced with the number of lines to scroll"</comment>
2020-10-06 09:56:59 -07:00
</data>
<data name="ScrollDownPageCommandKey" xml:space="preserve">
<value>Scroll down one page</value>
</data>
<data name="ScrollUpCommandKey" xml:space="preserve">
2020-10-27 03:19:52 +02:00
<value>Scroll up</value>
</data>
<data name="ScrollUpSeveralRowsCommandKey" xml:space="preserve">
<value>Scroll up {0} line(s)</value>
<comment>{0} will be replaced with the number of lines to scroll"</comment>
2020-10-06 09:56:59 -07:00
</data>
<data name="ScrollUpPageCommandKey" xml:space="preserve">
<value>Scroll up one page</value>
</data>
2020-12-09 02:28:41 +09:00
<data name="ScrollToTopCommandKey" xml:space="preserve">
<value>Scroll to the top of history</value>
</data>
<data name="ScrollToBottomCommandKey" xml:space="preserve">
<value>Scroll to the bottom of history</value>
</data>
Experimental: add support for scrollbar marks (#12948)
Adds support for marks in the scrollbar. These marks can be added in 3
ways:
* Via the iterm2 `OSC 1337 ; SetMark` sequence
* Via the `addMark` action
* Automatically when the `experimental.autoMarkPrompts` per-profile
setting is enabled.
#11000 has more tracking for the big-picture for this feature, as well
as additional follow-ups. This set of functionality seemed complete
enough to send a review for now. That issue describes these how I wish
these actions to look in the fullness of time. This is simply the v0.1
from the hackathon last month.
#### Actions
* `addMark`: add a mark to the buffer. If there's a selection, use
place the mark covering at the selection. Otherwise, place the mark
on the cursor row.
- `color`: a color for the scrollbar mark. This is optional - defaults
to the `foreground` color of the current scheme if omitted.
* `scrollToMark`
- `direction`: `["first", "previous", "next", "last"]`
* `clearMark`: Clears marks at the current postition (either the
selection if there is one, or the cursor position.
* `clearAllMarks`: Don't think this needs explanation.
#### Per-profile settings
* `experimental.autoMarkPrompts`: `bool`, default `false`.
* `experimental.showMarksOnScrollbar`: `bool`
## PR Checklist
* [x] Closes #1527
* [x] Closes #6232
## Detailed Description of the Pull Request / Additional comments
This is basically hackathon code. It's experimental! That's okay! We'll
figure the rest of the design in post.
Theoretically, I should make these actions `experimental.` as well, but
it seemed like since the only way to see these guys was via the
`experimental.showMarksOnScrollbar` setting, you've already broken
yourself into experimental jail, and you know what you're doing.
Things that won't work as expected:
* resizing, ESPECIALLY reflowing
* Clearing the buffer with ED sequences / Clear Buffer
I could theoretically add velocity around this in the `TermControl`
layer. Always prevent marks from being visible, ignore all the actions.
Marks could still be set by VT and automark, but they'd be useless.
Next up priorities:
* Making this work with the FinalTerm sequences
* properly speccing
* adding support for `showMarksOnScrollbar: flags(categories)`, so you
can only display errors on the scrollbar
* adding the `category` flag to the `addMark` action
## Validation Steps Performed
I like using it quite a bit. The marks can get noisy if you have them
emitted on every prompt and the buffer has 9000 lines. But that's the
beautiful thing, the actions work even if the marks aren't visible, so
you can still scroll between prompts.
<details>
<summary>Settings blob</summary>
```jsonc
// actions
{ "keys": "ctrl+up", "command": { "action": "scrollToMark", "direction": "previous" }, "name": "Previous mark" },
{ "keys": "ctrl+down", "command": { "action": "scrollToMark", "direction": "next" }, "name": "Next mark" },
{ "keys": "ctrl+pgup", "command": { "action": "scrollToMark", "direction": "first" }, "name": "First mark" },
{ "keys": "ctrl+pgdn", "command": { "action": "scrollToMark", "direction": "last" }, "name": "Last mark" },
{ "command": { "action": "addMark" } },
{ "command": { "action": "addMark", "color": "#ff00ff" } },
{ "command": { "action": "addMark", "color": "#0000ff" } },
{ "command": { "action": "clearAllMarks" } },
// profiles.defaults
"experimental.autoMarkPrompts": true,
"experimental.showMarksOnScrollbar": true,
```
</details>
2022-06-09 16:10:16 -05:00
<data name="ScrollToPreviousMarkCommandKey" xml:space="preserve">
2022-07-22 14:01:32 -04:00
<value>Scroll to the previous mark</value>
Experimental: add support for scrollbar marks (#12948)
Adds support for marks in the scrollbar. These marks can be added in 3
ways:
* Via the iterm2 `OSC 1337 ; SetMark` sequence
* Via the `addMark` action
* Automatically when the `experimental.autoMarkPrompts` per-profile
setting is enabled.
#11000 has more tracking for the big-picture for this feature, as well
as additional follow-ups. This set of functionality seemed complete
enough to send a review for now. That issue describes these how I wish
these actions to look in the fullness of time. This is simply the v0.1
from the hackathon last month.
#### Actions
* `addMark`: add a mark to the buffer. If there's a selection, use
place the mark covering at the selection. Otherwise, place the mark
on the cursor row.
- `color`: a color for the scrollbar mark. This is optional - defaults
to the `foreground` color of the current scheme if omitted.
* `scrollToMark`
- `direction`: `["first", "previous", "next", "last"]`
* `clearMark`: Clears marks at the current postition (either the
selection if there is one, or the cursor position.
* `clearAllMarks`: Don't think this needs explanation.
#### Per-profile settings
* `experimental.autoMarkPrompts`: `bool`, default `false`.
* `experimental.showMarksOnScrollbar`: `bool`
## PR Checklist
* [x] Closes #1527
* [x] Closes #6232
## Detailed Description of the Pull Request / Additional comments
This is basically hackathon code. It's experimental! That's okay! We'll
figure the rest of the design in post.
Theoretically, I should make these actions `experimental.` as well, but
it seemed like since the only way to see these guys was via the
`experimental.showMarksOnScrollbar` setting, you've already broken
yourself into experimental jail, and you know what you're doing.
Things that won't work as expected:
* resizing, ESPECIALLY reflowing
* Clearing the buffer with ED sequences / Clear Buffer
I could theoretically add velocity around this in the `TermControl`
layer. Always prevent marks from being visible, ignore all the actions.
Marks could still be set by VT and automark, but they'd be useless.
Next up priorities:
* Making this work with the FinalTerm sequences
* properly speccing
* adding support for `showMarksOnScrollbar: flags(categories)`, so you
can only display errors on the scrollbar
* adding the `category` flag to the `addMark` action
## Validation Steps Performed
I like using it quite a bit. The marks can get noisy if you have them
emitted on every prompt and the buffer has 9000 lines. But that's the
beautiful thing, the actions work even if the marks aren't visible, so
you can still scroll between prompts.
<details>
<summary>Settings blob</summary>
```jsonc
// actions
{ "keys": "ctrl+up", "command": { "action": "scrollToMark", "direction": "previous" }, "name": "Previous mark" },
{ "keys": "ctrl+down", "command": { "action": "scrollToMark", "direction": "next" }, "name": "Next mark" },
{ "keys": "ctrl+pgup", "command": { "action": "scrollToMark", "direction": "first" }, "name": "First mark" },
{ "keys": "ctrl+pgdn", "command": { "action": "scrollToMark", "direction": "last" }, "name": "Last mark" },
{ "command": { "action": "addMark" } },
{ "command": { "action": "addMark", "color": "#ff00ff" } },
{ "command": { "action": "addMark", "color": "#0000ff" } },
{ "command": { "action": "clearAllMarks" } },
// profiles.defaults
"experimental.autoMarkPrompts": true,
"experimental.showMarksOnScrollbar": true,
```
</details>
2022-06-09 16:10:16 -05:00
</data>
<data name="ScrollToNextMarkCommandKey" xml:space="preserve">
<value>Scroll to the next mark</value>
</data>
<data name="ScrollToFirstMarkCommandKey" xml:space="preserve">
<value>Scroll to the first mark</value>
</data>
<data name="ScrollToLastMarkCommandKey" xml:space="preserve">
<value>Scroll to the last mark</value>
</data>
<data name="AddMarkCommandKey" xml:space="preserve">
<value>Add a scroll mark</value>
</data>
<data name="AddMarkWithColorCommandKey" xml:space="preserve">
<value>Add a scroll mark, color:{0}</value>
<comment>{Locked="color"}. "color" is a literal parameter name that shouldn't be translated. {0} will be replaced with a color in hexadecimal format, like `#123456`</comment>
</data>
<data name="ClearMarkCommandKey" xml:space="preserve">
<value>Clear mark</value>
</data>
<data name="ClearAllMarksCommandKey" xml:space="preserve">
<value>Clear all marks</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="SendInputCommandKey" xml:space="preserve">
2025-09-03 13:36:10 -07:00
<value>Send input: "{0}"</value>
2020-10-06 09:56:59 -07:00
<comment>{0} will be replaced with a string of input as defined by the user</comment>
</data>
<data name="SetColorSchemeCommandKey" xml:space="preserve">
<value>Set color scheme to {0}</value>
<comment>{0} will be replaced with the name of a color scheme as defined by the user.</comment>
</data>
<data name="SetTabColorCommandKey" xml:space="preserve">
<value>Set tab color to {0}</value>
<comment>{0} will be replaced with a color, displayed in hexadecimal (#RRGGBB) notation.</comment>
</data>
<data name="SplitHorizontalCommandKey" xml:space="preserve">
<value>Split pane horizontally</value>
</data>
Move Pane to Tab (GH7075) (#10780)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Add functionality to move a pane to another tab. If the tab index is greater than the number of current tabs a new tab will be created with the pane as its root. Similarly, if the last pane on a tab is moved to another tab, the original tab will be closed.
This is largely complete, but I know that I'm messing around with things that I am unfamiliar with, and would like to avoid footguns where possible.
<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? -->
## References
#4587
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #7075
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [x] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
Things done:
- Moving a pane to a new tab appears to work. Moving a pane to an existing tab mostly works. Moving a pane back to its original tab appears to work.
- Set up {Attach,Detach}Pane methods to add or remove a pane from a pane. Detach is slightly different than Close in that we want to persist the tree structure and terminal controls.
- Add `Detached` event on a pane that can be subscribed to to remove other event handlers if desired.
- Added simple WalkTree abstraction for one-off recursion use cases that calls a provided function on each pane in order (and optionally terminates early).
- Fixed an in-prod bug with closing panes. Specifically, if you have a tree (1; 2 3) and close the 1 pane, then 3 will lose its borders because of these lines clearing the border on both children https://github.com/microsoft/terminal/blob/main/src/cascadia/TerminalApp/Pane.cpp#L1197-L1201 .
To do:
- Right now I have `TerminalTab` as a friend class of `Pane` so I can access some extra properties in my `WalkTree` callbacks, but there is probably a better choice for the abstraction boundary.
Next Steps:
- In a future PR Drag & Drop handlers could be added that utilize the Attach/Detach infrastructure to provide a better UI.
- Similarly once this is working, it should be possible to convert an entire tab into a pane on an existing tab (Tab::DetachRoot on original tab followed by Tab::AttachPane on the target tab).
- Its been 10 years, I just really want to use concepts already.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Manual testing by creating pane(s), and moving them between tabs and creating new tabs and destroying tabs by moving the last remaining pane.
2021-08-12 12:41:17 -04:00
<data name="MovePaneCommandKey" xml:space="preserve">
<value>Move pane</value>
</data>
2023-05-01 10:20:23 -05:00
<data name="MovePaneToNewWindowCommandKey" xml:space="preserve">
<value>Move pane to new window</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="SplitPaneCommandKey" xml:space="preserve">
<value>Split pane</value>
</data>
<data name="SplitVerticalCommandKey" xml:space="preserve">
<value>Split pane vertically</value>
</data>
<data name="SwitchToTabCommandKey" xml:space="preserve">
<value>Switch to tab</value>
</data>
2021-07-22 08:48:36 -05:00
<data name="SwitchToLastTabCommandKey" xml:space="preserve">
<value>Switch to the last tab</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="TabSearchCommandKey" xml:space="preserve">
2024-08-21 11:13:39 -07:00
<value>Search for tab...</value>
2020-10-06 09:56:59 -07:00
</data>
<data name="ToggleAlwaysOnTopCommandKey" xml:space="preserve">
<value>Toggle always on top mode</value>
</data>
<data name="ToggleCommandPaletteCommandKey" xml:space="preserve">
<value>Toggle command palette</value>
</data>
2023-08-15 08:48:09 -05:00
<data name="SuggestionsCommandKey" xml:space="preserve">
2024-04-10 05:41:43 +05:30
<value>Open suggestions</value>
2023-08-15 08:48:09 -05:00
</data>
2020-12-03 18:15:31 +02:00
<data name="ToggleCommandPaletteCommandLineModeCommandKey" xml:space="preserve">
<value>Toggle command palette in command line mode</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="ToggleFocusModeCommandKey" xml:space="preserve">
<value>Toggle focus mode</value>
<comment>"Focus mode" is a mode with minimal UI elements, for a distraction-free experience</comment>
</data>
2022-01-10 11:21:05 -05:00
<data name="EnableFocusModeCommandKey" xml:space="preserve">
<value>Enable focus mode</value>
</data>
<data name="DisableFocusModeCommandKey" xml:space="preserve">
<value>Disable focus mode</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="ToggleFullscreenCommandKey" xml:space="preserve">
<value>Toggle fullscreen</value>
</data>
2022-01-10 11:21:05 -05:00
<data name="EnableFullScreenCommandKey" xml:space="preserve">
<value>Enable fullscreen</value>
</data>
<data name="DisableFullScreenCommandKey" xml:space="preserve">
<value>Disable fullscreen</value>
</data>
<data name="EnableMaximizedCommandKey" xml:space="preserve">
<value>Maximize window</value>
</data>
<data name="DisableMaximizedCommandKey" xml:space="preserve">
<value>Restore maximized window</value>
</data>
2021-08-02 17:04:57 -04:00
<data name="ToggleSplitOrientationCommandKey" xml:space="preserve">
<value>Toggle pane split orientation</value>
</data>
2020-10-06 09:56:59 -07:00
<data name="TogglePaneZoomCommandKey" xml:space="preserve">
<value>Toggle pane zoom</value>
</data>
2021-02-08 20:03:55 +02:00
<data name="TogglePaneReadOnlyCommandKey" xml:space="preserve">
<value>Toggle pane read-only mode</value>
</data>
2023-03-22 17:32:56 +00:00
<data name="EnablePaneReadOnlyCommandKey" xml:space="preserve">
<value>Enable pane read-only mode</value>
</data>
<data name="DisablePaneReadOnlyCommandKey" xml:space="preserve">
<value>Disable pane read-only mode</value>
</data>
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 14:40:22 -06:00
<data name="ToggleShaderEffectsCommandKey" xml:space="preserve">
<value>Toggle terminal visual effects</value>
2020-10-06 09:56:59 -07:00
</data>
2020-12-04 17:54:59 -06:00
<data name="BreakIntoDebuggerCommandKey" xml:space="preserve">
<value>Break into the debugger</value>
</data>
2021-01-04 16:14:51 -06:00
<data name="OpenSettingsUICommandKey" xml:space="preserve">
2024-04-10 05:41:43 +05:30
<value>Open settings</value>
2021-01-04 16:14:51 -06:00
</data>
Add support for renaming windows (#9662)
## Summary of the Pull Request
This PR adds support for renaming windows.


It does so through two new actions:
* `renameWindow` takes a `name` parameter, and attempts to set the window's name
to the provided name. This is useful if you always want to hit <kbd>F3</kbd>
and rename a window to "foo" (READ: probably not that useful)
* `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a
`TextBox`. When the user hits Ok, it'll request a rename for the provided
value. This lets the user pick a new name for the window at runtime.
In both cases, if there's already a window with that name, then the monarch will
reject the rename, and pop a `Toast` in the window informing the user that the
rename failed. Nifty!
## References
* Builds on the toasts from #9523
* #5000 - process model megathread
## PR Checklist
* [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747
* [x] I work here
* [x] Tests addded (and pass with the help of #9660)
* [ ] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews.
> PAIN: We can't immediately focus the textbox in the TeachingTip. It's
> not technically focusable until it is opened. However, it doesn't
> provide an even tto tell us when it is opened. That's tracked in
> microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to
> click on the text box manually.
> We're also not using a ContentDialog for this, because in Xaml
> Islands a text box in a ContentDialog won't recieve _any_ keypresses.
> Fun!
## Validation Steps Performed
I've been playing with
```json
{ "keys": "f1", "command": "identifyWindow" },
{ "keys": "f2", "command": "identifyWindows" },
{ "keys": "f3", "command": "openWindowRenamer" },
{ "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } },
{ "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } },
```
and they seem to work as expected
2021-04-02 11:00:04 -05:00
<data name="RenameWindowCommandKey" xml:space="preserve">
<value>Rename window to "{0}"</value>
<comment>{0} will be replaced with a user-defined string</comment>
</data>
<data name="ResetWindowNameCommandKey" xml:space="preserve">
<value>Reset window name</value>
</data>
Add support for "workspaces" based on window names (redux) (#20314)
This adds a new feature to the Windows Terminal: "Workspaces"
Workspaces are very shamelessly inspired by Edge workspaces of the same
name.
The core idea is that when users name a window and they close that
window, we will persist that Windows layout and buffers, seperately from
the rest of window restoration. So a user can open a named window, open
some profiles, some panes, do some stuff in it, then close it, and we
will keep that state around for the next time the user opens that window
name.
Unnamed windows still behave the same. If you close an unnamed window,
and it's not the last window, then we won't persist the state of it.
To facilitate restoring named windows, we add a `openWorkspace` action.
This allows us to persist the open workspace action in the window layout
restoration path. So when we deserialize the list of tab layouts, and
open workspace action will tell us, hey, go retrieve this known
workspace from the state.json, instead of trying to serialize the window
state in two places.
As demoed in the video, we add a flyout to list the windows that the
user has open, and the named workspaces that they have saved. This
allows users to quickly reopen previously closed workspaces, as well as
quickly rename a window, thereby adding it to the list of saved
workspaces. This button can also be hidden using the theme settings.
Closes #17084
(this is a reboot of #20162, but with the event from #20311)
2026-06-16 16:59:17 -05:00
<data name="OpenWorkspaceCommandKey" xml:space="preserve">
<value>Open workspace "{0}"</value>
<comment>{0} will be replaced with the workspace name</comment>
</data>
<data name="OpenWorkspaceDefaultCommandKey" xml:space="preserve">
<value>Open workspace</value>
</data>
Add support for renaming windows (#9662)
## Summary of the Pull Request
This PR adds support for renaming windows.


It does so through two new actions:
* `renameWindow` takes a `name` parameter, and attempts to set the window's name
to the provided name. This is useful if you always want to hit <kbd>F3</kbd>
and rename a window to "foo" (READ: probably not that useful)
* `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a
`TextBox`. When the user hits Ok, it'll request a rename for the provided
value. This lets the user pick a new name for the window at runtime.
In both cases, if there's already a window with that name, then the monarch will
reject the rename, and pop a `Toast` in the window informing the user that the
rename failed. Nifty!
## References
* Builds on the toasts from #9523
* #5000 - process model megathread
## PR Checklist
* [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747
* [x] I work here
* [x] Tests addded (and pass with the help of #9660)
* [ ] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews.
> PAIN: We can't immediately focus the textbox in the TeachingTip. It's
> not technically focusable until it is opened. However, it doesn't
> provide an even tto tell us when it is opened. That's tracked in
> microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to
> click on the text box manually.
> We're also not using a ContentDialog for this, because in Xaml
> Islands a text box in a ContentDialog won't recieve _any_ keypresses.
> Fun!
## Validation Steps Performed
I've been playing with
```json
{ "keys": "f1", "command": "identifyWindow" },
{ "keys": "f2", "command": "identifyWindows" },
{ "keys": "f3", "command": "openWindowRenamer" },
{ "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } },
{ "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } },
```
and they seem to work as expected
2021-04-02 11:00:04 -05:00
<data name="OpenWindowRenamerCommandKey" xml:space="preserve">
2024-08-21 11:13:39 -07:00
<value>Rename window...</value>
Add support for renaming windows (#9662)
## Summary of the Pull Request
This PR adds support for renaming windows.


It does so through two new actions:
* `renameWindow` takes a `name` parameter, and attempts to set the window's name
to the provided name. This is useful if you always want to hit <kbd>F3</kbd>
and rename a window to "foo" (READ: probably not that useful)
* `openWindowRenamer` is more interesting: it opens a `TeachingTip` with a
`TextBox`. When the user hits Ok, it'll request a rename for the provided
value. This lets the user pick a new name for the window at runtime.
In both cases, if there's already a window with that name, then the monarch will
reject the rename, and pop a `Toast` in the window informing the user that the
rename failed. Nifty!
## References
* Builds on the toasts from #9523
* #5000 - process model megathread
## PR Checklist
* [x] Closes https://github.com/microsoft/terminal/projects/5#card-50771747
* [x] I work here
* [x] Tests addded (and pass with the help of #9660)
* [ ] Requires documentation to be updated
## Detailed Description of the Pull Request / Additional comments
I'm sending this PR while finishing up the tests. I figured I'll have time to sneak them in before I get the necessary reviews.
> PAIN: We can't immediately focus the textbox in the TeachingTip. It's
> not technically focusable until it is opened. However, it doesn't
> provide an even tto tell us when it is opened. That's tracked in
> microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to
> click on the text box manually.
> We're also not using a ContentDialog for this, because in Xaml
> Islands a text box in a ContentDialog won't recieve _any_ keypresses.
> Fun!
## Validation Steps Performed
I've been playing with
```json
{ "keys": "f1", "command": "identifyWindow" },
{ "keys": "f2", "command": "identifyWindows" },
{ "keys": "f3", "command": "openWindowRenamer" },
{ "keys": "f4", "command": { "action": "renameWindow", "name": "foo" } },
{ "keys": "f5", "command": { "action": "renameWindow", "name": "bar" } },
```
and they seem to work as expected
2021-04-02 11:00:04 -05:00
</data>
2023-07-20 11:09:21 -05:00
<data name="DisplayWorkingDirectoryCommandKey" xml:space="preserve">
<value>Display Terminal's current working directory</value>
</data>
2021-04-28 17:13:28 -05:00
<data name="GlobalSummonCommandKey" xml:space="preserve">
2022-03-04 19:39:58 +01:00
<value>Show/Hide the Terminal window</value>
2021-04-28 17:13:28 -05:00
</data>
<data name="QuakeModeCommandKey" xml:space="preserve">
2022-03-04 19:39:58 +01:00
<value>Show/Hide Quake window</value>
<comment>Quake is a well-known computer game and isn't related to earthquakes, etc. See https://en.wikipedia.org/wiki/Quake_(video_game)</comment>
2021-04-28 17:13:28 -05:00
</data>
2021-05-21 16:55:57 -05:00
<data name="FocusPaneCommandKey" xml:space="preserve">
<value>Focus pane {0}</value>
<comment>{0} will be replaced with a user-specified number</comment>
</data>
2022-01-12 10:58:38 -06:00
<data name="ExportBufferToPathCommandKey" xml:space="preserve">
<value>Export text to {0}</value>
<comment>{0} will be replaced with a user-specified file path</comment>
</data>
<data name="ExportBufferCommandKey" xml:space="preserve">
<value>Export text</value>
</data>
2021-09-02 09:59:42 -05:00
<data name="ClearAllCommandKey" xml:space="preserve">
2021-09-29 05:24:46 -05:00
<value>Clear buffer</value>
2021-09-02 09:59:42 -05:00
<comment>A command to clear the entirety of the Terminal output buffer</comment>
</data>
<data name="ClearViewportCommandKey" xml:space="preserve">
2021-09-29 05:24:46 -05:00
<value>Clear viewport</value>
2021-09-02 09:59:42 -05:00
<comment>A command to clear the active viewport of the Terminal</comment>
</data>
<data name="ClearScrollbackCommandKey" xml:space="preserve">
2021-09-29 05:24:46 -05:00
<value>Clear scrollback</value>
2021-09-02 09:59:42 -05:00
<comment>A command to clear the part of the buffer above the viewport</comment>
</data>
2022-06-07 21:31:02 +02:00
<data name="DefaultWindowsConsoleName" xml:space="preserve">
<value>Let Windows decide</value>
<comment>This is the default option if a user doesn't choose to override Microsoft's choice of a Terminal.</comment>
</data>
2021-04-28 03:43:30 -07:00
<data name="InboxWindowsConsoleAuthor" xml:space="preserve">
<value>Microsoft Corporation</value>
<comment>Paired with `InboxWindowsConsoleName`, this is the application author... which is us: Microsoft.</comment>
</data>
<data name="InboxWindowsConsoleName" xml:space="preserve">
<value>Windows Console Host</value>
<comment>Name describing the usage of the classic windows console as the terminal UI. (`conhost.exe`)</comment>
</data>
2021-09-09 10:03:03 -04:00
<data name="QuitCommandKey" xml:space="preserve">
<value>Quit the Terminal</value>
</data>
2022-01-12 13:06:31 -06:00
<data name="SetOpacityParentCommandName" xml:space="preserve">
2024-08-21 11:13:39 -07:00
<value>Set background opacity...</value>
2022-01-12 13:06:31 -06:00
</data>
<data name="IncreaseOpacityCommandKey" xml:space="preserve">
<value>Increase background opacity by {0}%</value>
<comment>A command to change how transparent the background of the window is</comment>
</data>
<data name="DecreaseOpacityCommandKey" xml:space="preserve">
<value>Decrease background opacity by {0}%</value>
<comment>A command to change how transparent the background of the window is</comment>
</data>
<data name="AdjustOpacityCommandKey" xml:space="preserve">
<value>Set background opacity to {0}%</value>
<comment>A command to change how transparent the background of the window is</comment>
</data>
2022-01-11 15:08:15 -05:00
<data name="RestoreLastClosedCommandKey" xml:space="preserve">
<value>Restore the last closed pane or tab</value>
</data>
2022-05-06 13:06:49 -07:00
<data name="SelectAllCommandKey" xml:space="preserve">
<value>Select all text</value>
</data>
2022-05-20 16:04:53 -07:00
<data name="MarkModeCommandKey" xml:space="preserve">
<value>Toggle mark mode</value>
<comment>A command that will toggle "mark mode". This is a mode in the application where the user can mark the text by selecting portions of the text.</comment>
</data>
2022-06-07 03:55:17 -07:00
<data name="ToggleBlockSelectionCommandKey" xml:space="preserve">
<value>Toggle block selection</value>
</data>
2022-06-30 18:44:39 -07:00
<data name="SwitchSelectionEndpointCommandKey" xml:space="preserve">
<value>Switch selection endpoint</value>
</data>
Implement EnableColorSelection (#13429)
## Summary of the Pull Request
As described in #9583, this change implements the legacy conhost "EnableColorSelection" feature.
## Detailed Description of the Pull Request / Additional comments
@zadjii-msft was super nice and provided the outline/plumbing (WinRT classes and such) as a hackathon-type project (thank you!)--a "SelectionColor" runtimeclass, a ColorSelection method on the ControlCore runtimeclass, associated plumbing through the layers; plus the action-and-args plumbing to allow hooking up a basic "ColorSelection" action, which allows you to put actions in your settings JSON like so:
```json
{
"command":
{
"action": "experimental.colorSelection",
"foreground": "#0f3"
},
"keys": "alt+4"
},
```
On top of that foundation, I added a couple of things:
* The ability to specify indexes for colors, in addition to RGB and RRGGBB colors.
- It's a bit hacky, because there are some conversions that fight against sneaking an "I'm an index" flag in the alpha channel.
* A new "matchMode" parameter on the action, allowing you to say if you want to only color the current selection ("0") or all matches ("1").
- I made it an int, because I'd like to enable at least one other "match mode" later, but it requires me/someone to fix up search.cpp to handle regex first.
- Search used an old UIA "ColorSelection" method which was previously `E_NOTIMPL`, but is now wired up. Don't know what/if anything else uses this.
* An uber-toggle setting, "EnableColorSelection", which allows you to set a single `bool` in your settings JSON, to light up all the keybindings you would expect from the legacy "EnableColorSelection" feature:
- alt+[0..9]: color foreground
- alt+shift+[0..9]: color foreground, all matches
- ctrl+[0..9]: color background
- ctrl+shift+[0..9]: color background, all matches
* A few of the actions cannot be properly invoked via their keybindings, due to #13124. `*!*` But they work if you do them from the command palette.
* If you have "`EnableColorSelection : true`" in your settings JSON, but then specify a different action in your JSON that uses the same key binding as a color selection keybinding, your custom one wins, which I think is the right thing.
* I fixed what I think was a bug in search.cpp, which also affected the legacy EnableColorSelection feature: due to a non-inclusive coordinate comparison, you were not allowed to color a single character; but I see no reason why that should be disallowed. Now you can make all your `X`s red if you like.
"Soft" spots:
* I was a bit surprised at some of the helpers I had to provide in textBuffer.cpp. Perhaps there are existing methods that I didn't find?
* Localization? Because there are so many (40!) actions, I went to some trouble to try to provide nice command/arg descriptions. But I don't know how localization works…
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #9583
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed *(what would be the right place to add tests for this?)*
* [ ] 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. *(is this needed?)*
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx
## Validation Steps Performed
Just manual testing.
2022-08-31 16:54:29 -07:00
<data name="ColorSelection_allMatches" xml:space="preserve">
<value>all matches</value>
<comment>This is used in the description of an action which changes the color of selected text, to indicate that not only the selected text will be colored, but also all matching text.</comment>
</data>
<data name="ColorSelection_fg_action" xml:space="preserve">
<value>Color selection, foreground: {0}{1}</value>
<comment>This is the description of an action which changes the color of selected text. {0}: the color. {1}: empty string OR a clause indicating that all matching text will be colored (ColorSelection_allMatches).</comment>
</data>
<data name="ColorSelection_bg_action" xml:space="preserve">
<value>Color selection, background: {0}{1}</value>
<comment>This is the description of an action which changes the background color of selected text. {0}: the color. {1}: empty string OR a clause indicating that all matching text will be colored (ColorSelection_allMatches).</comment>
</data>
<data name="ColorSelection_fg_bg_action" xml:space="preserve">
<value>Color selection, foreground: {0}, background: {1}{2}</value>
<comment>This is the description of an action which changes the color of selected text and the background. {0}: the foreground color. {1}: the background color. {2}: empty string OR a clause indicating that all matching text will be colored (ColorSelection_allMatches).</comment>
</data>
<data name="ColorSelection_default_action" xml:space="preserve">
<value>Color selection, (default foreground/background){0}</value>
<comment>This is the description of an action which changes the color of selected text and the background to the default colors. {0}: empty string OR a clause indicating that all matching text will be colored (ColorSelection_allMatches).</comment>
</data>
<data name="ColorSelection_defaultColor" xml:space="preserve">
<value>[default]</value>
<comment>This is used in the description of an action which changes the color of selected text, as a placeholder for a color, to indicate that the default (foreground or background) color will be used.</comment>
</data>
<data name="ColorSelection_Black" xml:space="preserve">
<value>black</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_Red" xml:space="preserve">
<value>red</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_Green" xml:space="preserve">
<value>green</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_Yellow" xml:space="preserve">
<value>yellow</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_Blue" xml:space="preserve">
<value>blue</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_Purple" xml:space="preserve">
<value>purple</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_Cyan" xml:space="preserve">
<value>cyan</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_White" xml:space="preserve">
<value>white</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_BrightBlack" xml:space="preserve">
<value>bright black</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_BrightRed" xml:space="preserve">
<value>bright red</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_BrightGreen" xml:space="preserve">
<value>bright green</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_BrightYellow" xml:space="preserve">
<value>bright yellow</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_BrightBlue" xml:space="preserve">
<value>bright blue</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_BrightPurple" xml:space="preserve">
<value>bright purple</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_BrightCyan" xml:space="preserve">
<value>bright cyan</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
<data name="ColorSelection_BrightWhite" xml:space="preserve">
<value>bright white</value>
<comment>A color used in the "ColorSelection" action.</comment>
</data>
2022-08-31 12:06:05 -07:00
<data name="ExpandSelectionToWordCommandKey" xml:space="preserve">
<value>Expand selection to word</value>
</data>
2023-05-10 22:32:27 -05:00
<data name="ShowContextMenuCommandKey" xml:space="preserve">
<value>Show context menu</value>
</data>
2022-08-26 19:27:04 +02:00
<data name="CloseOtherPanesCommandKey" xml:space="preserve">
<value>Close all other panes</value>
</data>
2023-07-19 10:45:25 -05:00
<data name="ToggleBroadcastInputCommandKey" xml:space="preserve">
<value>Toggle broadcast input to all panes</value>
<comment>When enabled, input will go to all panes in this tab simultaneously</comment>
</data>
2023-04-28 17:50:12 -05:00
<data name="RestartConnectionKey" xml:space="preserve">
2026-04-29 11:54:43 -07:00
<value>Restart session</value>
2023-04-28 17:50:12 -05:00
</data>
2024-03-26 10:56:31 -07:00
<data name="OpenScratchpadKey" xml:space="preserve">
<value>Open scratchpad</value>
</data>
Add the ability to select a whole command (or its output) (#14807)
Adds two new commands, `selectOutput` and `selectCommand`. These don't
do much without shell integration enabled, unfortunately. If you do
enable it, however, you can use these commands to quickly navigate the
history to select whole commands (or their output).
Some sample JSON:
```json
{ "keys": "ctrl+shift+<", "command": { "action": "selectCommand", "direction": "prev" } },
{ "keys": "ctrl+shift+>", "command": { "action": "selectCommand", "direction": "next" } },
{ "keys": "ctrl+shift+[", "command": { "action": "selectOutput", "direction": "prev" } },
{ "keys": "ctrl+shift+]", "command": { "action": "selectOutput", "direction": "next" } },
```
**Demo gifs** in
https://github.com/microsoft/terminal/issues/4588#issuecomment-1352042789
closes #4588
Tested manually.
<details>
<summary>CMD.exe user? It's dangerous to go alone! Take this.</summary>
Surely, there's a simpler way to do it, this is adapted from my own
script.
```cmd
prompt $e]133;D$e\$e]133;A$e\$e\$e]9;9;$P$e\$e[30;107m[$T]$e[97;46m$g$P$e[36;49m$g$e[0m$e[K$_$e[0m$e[94m%username%$e[0m@$e[32m%computername%$e[0m$G$e]133;B$e\
```
</details>
2023-04-20 07:34:58 -05:00
<data name="SelectOutputNextCommandKey" xml:space="preserve">
<value>Select next command output</value>
</data>
<data name="SelectOutputPreviousCommandKey" xml:space="preserve">
<value>Select previous command output</value>
</data>
<data name="SelectCommandNextCommandKey" xml:space="preserve">
<value>Select next command</value>
</data>
<data name="SelectCommandPreviousCommandKey" xml:space="preserve">
<value>Select previous command</value>
</data>
2023-06-21 19:24:45 +02:00
<data name="SearchForTextCommandKey" xml:space="preserve">
<value>Search {0}</value>
<comment>{0} will be replaced with a user-specified URL to a web page</comment>
</data>
<data name="SearchWebCommandKey" xml:space="preserve">
<value>Search the web for selected text</value>
<comment>This will open a web browser to search for some user-selected text</comment>
</data>
2023-09-18 11:55:05 -05:00
<data name="OpenAboutCommandKey" xml:space="preserve">
<value>Open about dialog</value>
<comment>This will open the "about" dialog, to display version info and other documentation</comment>
</data>
2024-07-02 07:27:20 -04:00
<data name="SaveSnippetNamePrefix" xml:space="preserve">
<value>Save Snippet</value>
</data>
2024-07-17 15:28:30 -07:00
<data name="QuickFixCommandKey" xml:space="preserve">
<value>Open quick fix menu</value>
</data>
2024-12-05 07:18:45 -05:00
<data name="OpenCWDCommandKey" xml:space="preserve">
<value>Open current working directory</value>
</data>
Add support for "workspaces" based on window names (redux) (#20314)
This adds a new feature to the Windows Terminal: "Workspaces"
Workspaces are very shamelessly inspired by Edge workspaces of the same
name.
The core idea is that when users name a window and they close that
window, we will persist that Windows layout and buffers, seperately from
the rest of window restoration. So a user can open a named window, open
some profiles, some panes, do some stuff in it, then close it, and we
will keep that state around for the next time the user opens that window
name.
Unnamed windows still behave the same. If you close an unnamed window,
and it's not the last window, then we won't persist the state of it.
To facilitate restoring named windows, we add a `openWorkspace` action.
This allows us to persist the open workspace action in the window layout
restoration path. So when we deserialize the list of tab layouts, and
open workspace action will tell us, hey, go retrieve this known
workspace from the state.json, instead of trying to serialize the window
state in two places.
As demoed in the video, we add a flyout to list the windows that the
user has open, and the named workspaces that they have saved. This
allows users to quickly reopen previously closed workspaces, as well as
quickly rename a window, thereby adding it to the list of saved
workspaces. This button can also be hidden using the theme settings.
Closes #17084
(this is a reboot of #20162, but with the event from #20311)
2026-06-16 16:59:17 -05:00
<data name="WorkspacesCommandKey" xml:space="preserve">
<value>Workspaces...</value>
</data>
2025-09-03 13:36:10 -07:00
<data name="CloseTab" xml:space="preserve">
<value>Close tab</value>
</data>
<data name="SendInput" xml:space="preserve">
<value>Send input</value>
</data>
<data name="SetFocusMode" xml:space="preserve">
<value>Set focus mode</value>
</data>
<data name="SetFullScreen" xml:space="preserve">
<value>Set full screen</value>
</data>
<data name="SetMaximized" xml:space="preserve">
<value>Set maximized</value>
</data>
<data name="SetColorScheme" xml:space="preserve">
<value>Set color scheme</value>
</data>
<data name="CloseOtherTabs" xml:space="preserve">
<value>Close other tabs</value>
</data>
<data name="CloseTabsAfter" xml:space="preserve">
<value>Close tabs after</value>
</data>
<data name="MoveTab" xml:space="preserve">
<value>Move tab</value>
</data>
<data name="FindMatch" xml:space="preserve">
<value>Find match</value>
</data>
<data name="SearchForText" xml:space="preserve">
<value>Search for text</value>
</data>
<data name="FocusPane" xml:space="preserve">
<value>Focus pane</value>
</data>
<data name="ExportBuffer" xml:space="preserve">
<value>Export buffer</value>
</data>
<data name="ClearBuffer" xml:space="preserve">
<value>Clear buffer</value>
</data>
<data name="MultipleActions" xml:space="preserve">
<value>Multiple actions</value>
</data>
<data name="AdjustOpacity" xml:space="preserve">
<value>Adjust opacity</value>
</data>
<data name="SelectCommand" xml:space="preserve">
<value>Select command</value>
</data>
<data name="SelectOutput" xml:space="preserve">
<value>Select output</value>
</data>
<data name="Suggestions" xml:space="preserve">
<value>Suggestions</value>
</data>
<data name="ColorSelection" xml:space="preserve">
<value>Color selection</value>
</data>
Add an Extensions page to the Settings UI (#18559)
This pull request adds an Extensions page to the Settings UI, which lets
you enable/disable extensions and see how they affect your settings
(i.e. adding/modifying profiles and adding color schemes). This page is
specifically designed for fragment extensions and dynamic profile
generators, but can be expanded on in the future as we develop a more
advanced extensions model.
App extensions extract the name and icon from the extension package and
display it in the UI. Dynamic profile generators extract the name and
icon from the generator and display it in the UI. We prefer to use the
display name for breadcrumbs when possible.
A "NEW" badge was added to the Extensions page's `NavigationViewItem` to
highlight that it's new. It goes away once the user visits it.
## Detailed Description of the Pull Request / Additional comments
- Settings Model changes:
- `FragmentSettings` represents a parsed json fragment extension.
- `FragmentProfileEntry` and `FragmentColorSchemeEntry` are used to
track profiles and color schemes added/modified
- `ExtensionPackage` bundles the `FragmentSettings` together. This is
how we represent multiple JSON files in one extension.
- `IDynamicProfileGenerator` exposes a `DisplayName` and `Icon`
- `ExtensionPackage`s created from app extensions extract the
`DisplayName` and `Icon` from the extension
- `ApplicationState` is used to track which badges have been dismissed
and prevent them from appearing again
- a `std::unordered_set` is used to keep track of the dismissed badges,
but we only expose a get and append function via the IDL to interact
with it
- Editor changes - view models:
- `ExtensionsViewModel` operates as the main view model for the page.
- `FragmentProfileViewModel` and `FragmentColorSchemeViewModel` are used
to reference specific components of fragments. They also provide support
for navigating to the linked profile or color scheme via the settings
UI!
- `ExtensionPackageViewModel` is a VM for a group of extensions exposed
by a single source. This is mainly needed because a single source can
have multiple JSON fragments in it. This is used for the navigators on
the main page. Can be extended to provide additional information (i.e.
package logo, package name, etc.)
- `CurrentExtensionPackage` is used to track which extension package is
currently in view, if applicable (similar to how the new tab menu page
works)
- Editor changes - views:
- `Extensions.xaml` uses _a lot_ of data templates. These are reused in
`ItemsControl`s to display extension components.
- `ExtensionPackageTemplateSelector` is used to display
`ExtensionPackage`s with metadata vs simple ones that just have a source
(i.e. Git)
- Added a `NewInfoBadge` style that is just an InfoBadge with "New" in
it instead of a number or an icon. Based on
https://github.com/microsoft/PowerToys/pull/36939
- The visibility is bound to a `get` call to the `ApplicationState`
conducted via the `ExtensionsPageViewModel`. The VM is also responsible
for updating the state.
- Lazy loading extension objects
- Since most instances of Terminal won't actually open the settings UI,
it doesn't make sense to create all the extension objects upon startup.
Instead, we defer creating those objects until the user actually
navigates to the Extensions page. This is most of the work that happened
in `CascadiaSettingsSerialization.cpp`. The `SettingsLoader` can be used
specifically to load and create the extension objects.
## Validation Steps
✅ Keyboard navigation feels right
✅ Screen reader reads all info on screen properly
✅ Accessibility Insights FastPass found no issues
✅ "Discard changes" retains subpage, but removes any changes
✅ Extensions page nav item displays a badge if page hasn't been visited
✅ The badge is dismissed when the user visits the page
## Follow-ups
- Streamline a process for adding extensions from the new page
- Long-term, we can reuse the InfoBadge system and make the following
minor changes:
- `SettingContainer`: display the badge and add logic to read/write
`ApplicationState` appropriately (similarly to above)
- `XPageViewModel`:
- count all the badges that will be displayed and expose/bind that to
`InfoBadge.Value`
- If a whole page is new, we can just style the badge using the
`NewInfoBadge` style
2025-05-28 12:03:02 -07:00
<data name="WslDistroGeneratorDisplayName" xml:space="preserve">
<value>WSL Distribution Profile Generator</value>
<comment>The display name of a dynamic profile generator for WSL distros</comment>
</data>
<data name="PowershellCoreProfileGeneratorDisplayName" xml:space="preserve">
<value>PowerShell Profile Generator</value>
<comment>The display name of a dynamic profile generator for PowerShell</comment>
</data>
<data name="AzureCloudShellGeneratorDisplayName" xml:space="preserve">
<value>Azure Cloud Shell Profile Generator</value>
<comment>The display name of a dynamic profile generator for Azure Cloud Shell</comment>
</data>
<data name="VisualStudioGeneratorDisplayName" xml:space="preserve">
<value>Visual Studio Profile Generator</value>
<comment>The display name of a dynamic profile generator for Visual Studio</comment>
</data>
<data name="SshHostGeneratorDisplayName" xml:space="preserve">
<value>SSH Host Profile Generator</value>
<comment>The display name of a dynamic profile generator for SSH hosts</comment>
</data>
2025-09-03 13:36:10 -07:00
<data name="DismissSelectionActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Dismiss selection</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="SingleLineActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Single line</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="WithControlSequencesActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>With control sequences</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="CopyFormattingActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Copy formatting</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="TabIndexActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Tab index</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="WindowActionArgumentLocalized" xml:space="preserve">
<value>Window</value>
</data>
<data name="ResizeDirectionActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Resize direction</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="FocusDirectionActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Focus direction</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="DirectionActionArgumentLocalized" xml:space="preserve">
<value>Direction</value>
</data>
<data name="DeltaActionArgumentLocalized" xml:space="preserve">
<value>Delta</value>
</data>
<data name="InputActionArgumentLocalized" xml:space="preserve">
<value>Input</value>
</data>
<data name="TargetActionArgumentLocalized" xml:space="preserve">
<value>Target</value>
</data>
<data name="IsFocusModeActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Is focus mode</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="IsMaximizedActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Is maximized</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="IsFullScreenActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Is full screen</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="SchemeNameActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Scheme name</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="TabColorActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Tab color</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="TitleActionArgumentLocalized" xml:space="preserve">
<value>Title</value>
</data>
<data name="CommandlineActionArgumentLocalized" xml:space="preserve">
<value>Commandline</value>
</data>
<data name="IndexActionArgumentLocalized" xml:space="preserve">
<value>Index</value>
</data>
<data name="RowsToScrollActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Rows to scroll</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="ColorActionArgumentLocalized" xml:space="preserve">
<value>Color</value>
</data>
<data name="LaunchModeActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Launch mode</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="NameActionArgumentLocalized" xml:space="preserve">
<value>Name</value>
</data>
<data name="KeyChordActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Key chord</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="SourceActionArgumentLocalized" xml:space="preserve">
<value>Source</value>
</data>
<data name="UseCommandlineActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Use commandline</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="SwitcherModeActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Switcher mode</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="QueryUrlActionArgumentLocalized" xml:space="preserve">
<value>Query URL</value>
</data>
<data name="DesktopActionArgumentLocalized" xml:space="preserve">
<value>Desktop</value>
</data>
<data name="MonitorActionArgumentLocalized" xml:space="preserve">
<value>Monitor</value>
</data>
<data name="ToggleVisibilityActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Toggle visibility</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="DropdownDurationActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Dropdown duration</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="IdActionArgumentLocalized" xml:space="preserve">
<value>Id</value>
</data>
<data name="PathActionArgumentLocalized" xml:space="preserve">
<value>Path</value>
</data>
<data name="ClearActionArgumentLocalized" xml:space="preserve">
<value>Clear</value>
</data>
<data name="OpacityActionArgumentLocalized" xml:space="preserve">
<value>Opacity</value>
</data>
<data name="RelativeActionArgumentLocalized" xml:space="preserve">
<value>Relative</value>
</data>
<data name="ForegroundActionArgumentLocalized" xml:space="preserve">
<value>Foreground</value>
</data>
<data name="BackgroundActionArgumentLocalized" xml:space="preserve">
<value>Background</value>
</data>
<data name="MatchModeActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Match mode</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="StartingDirectoryActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Starting directory</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="TabTitleActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Tab title</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="ProfileIndexActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Profile index</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="ProfileActionArgumentLocalized" xml:space="preserve">
<value>Profile</value>
</data>
<data name="SuppressApplicationTitleActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Suppress application title</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="ColorSchemeActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Color scheme</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="ElevateActionArgumentLocalized" xml:space="preserve">
<value>Elevate</value>
</data>
<data name="ReloadEnvironmentVariablesActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Reload environment variables</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="SplitDirectionActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Split direction</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="SplitModeActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Split mode</value>
2025-09-03 13:36:10 -07:00
</data>
<data name="SplitSizeActionArgumentLocalized" xml:space="preserve">
2026-02-12 18:25:08 -08:00
<value>Split size</value>
2025-09-03 13:36:10 -07:00
</data>
</root>