Compare commits

...

68 Commits

Author SHA1 Message Date
Carlos Zamora
fbfc761450 Redesign new tab menu page -> dropdown 2026-05-08 13:21:22 -07:00
Windows Console Service Bot
d3f76e7acf Localization Updates - main - 05/07/2026 03:04:15 (#20196)
Co-authored-by: Console Service Bot <consvc@microsoft.com>
2026-05-07 14:03:13 -05:00
Windows Console Service Bot
ea4cb8145f Localization Updates - main - 04/30/2026 03:04:35 (#20168)
Co-authored-by: Console Service Bot <consvc@microsoft.com>
2026-05-06 16:36:17 -05:00
Sushaanth Srinivasan
a325a2fa5a Fix settings error text legibility in High Contrast mode (#20098)
Closes #18147

`SystemErrorTextColor` doesn't adapt to High Contrast themes, so the
error details in the "Failed to reload settings" dialog are illegible
(yellow on cream in HC White, for example).

Fix: skip the `ErrorTextBrush` foreground override when High Contrast is
active, letting the text inherit the system HC text color from its
parent element. This matches the existing HC detection pattern used in
`TermControl.cpp` and `MainPage.cpp`.

Validated manually on High Contrast White and Night sky themes.

Co-authored-by: SushaanthSrinivasan <SushaanthSrinivasan@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 02:35:16 +00:00
nmurrell07
dadde2fb11 fix(resizePane): Mark as handled only when resize succeeds (#20001)
This fix addresses issue #19983 where resizePane actions unconditionally
consume keystrokes even when no resize can occur.

The fix follows the same pattern used for moveFocus and swapPane fixes:
- Changed Tab::ResizePane to return bool indicating success
- Changed TerminalPage::_ResizePane to return bool from ResizePane  
- Updated _HandleResizePane to set args.Handled() based on whether
resize succeeded

This allows the keychord to propagate to the terminal when no resize can
occur, matching the behavior of moveFocus and swapPane (#6129).

Closes #19983

---------

Co-authored-by: nmurrell07 <nmurrell07@users.noreply.github.com>
Co-authored-by: Dustin L. Howett <dustin@howett.net>
2026-05-05 19:42:48 +00:00
Dustin L. Howett
8edac5fb12 Don't allow overflowing lengths in WM_COPYDATA (#20185)
It is possible to craft a packet whose `len` is `0x80000001`.

We should not produce values that do not fit in size_t (on e.g. x86).

Reject them summarily.
2026-05-05 19:19:25 +00:00
Dustin L. Howett
dbc5177f7f Migrate some pull requests from OS (#20181)
Some work was required to ensure conhost builds.

---------

Co-authored-by: Dragos Sambotin <dragoss@microsoft.com>
Co-authored-by: Daniel Paoliello (HE HIM) <danpao@microsoft.com>
2026-05-05 00:34:13 +00:00
Carlos Zamora
b753e3dee3 Replace confirmCloseAllTabs with confirmOnClose (#20055)
## Summary of the Pull Request
Replaces the `warning.confirmCloseAllTabs` setting with a
`warning.confirmOnClose` enum setting that accepts the following:
- `never`: don't present a warning dialog when closing a session
- `automatic`: present a warning dialog when closing multiple tabs/panes
at once
- `always`: present a warning dialog when closing any session

The confirmation dialog contains a "don't ask me again" checkbox. When
checked, we update the setting to `never`.

This setting also affects the following actions:
- "close other tabs"
- "close tabs after"
- "close other panes"
- "quit"
The appropriate confirmation dialog is shown in these scenarios. We also
present an aggregate dialog instead of prompting the user once per
tab/pane. If there are no other tabs/panes, we don't present a dialog
and treat the key binding as unhandled (passing the key through).

## References and Relevant Issues
Iteration of #19944 

## Validation Steps Performed
- closing a tab:
   -  1 pane --> no dialog
   -  2 panes --> dialog
   -  action and middle clicking tab trigger same flow
- close all other tabs:
   -  no other tabs --> no dialog
   -  1 other tab --> dialog
- close all other panes:
   -  1 pane --> no dialog
   -  2 panes --> dialog
- close all tabs after the current tab:
   -  no tabs after --> no dialog (even if tabs before)
   -  1 tab after --> dialog
- close window:
   -  2 tabs --> dialog
   -  2 panes --> dialog
   -  1 tab with one pane --> no dialog
- Quit the Terminal:
   -  3 windows --> dialog
   - 1 window --> dialog
-  "don't ask me again" checkbox checked --> setting changed to "never"
-  "never" --> no dialog for scenarios above
-  "always" --> dialog always appears, even when closing a single pane

## PR Checklist
Closes #5301 
Closes #6641
"don't ask me again" checkbox is also mentioned in #10000 

Co-authored by @zadjii-msft
2026-05-04 10:43:34 -07:00
Carlos Zamora
a834313fb7 Add a setting for sending a notification on BEL (#20011)
## Summary of the Pull Request
Targets #20010 

Adds another `bellStyle` flag option. This sends a windows toast
notification to the user when a BEL is encountered

- [X] Closes #18605 
- [ ] Documentation updated

Heavily based on #19936 
Co-authored by @zadjii-msft
2026-05-04 10:38:17 -07:00
Carlos Zamora
059986ebce [Unpackaged] Fix taskbar glomming due to AUMID (#20064)
The bug was caused by an AUMID mismatch between the Taskbar's .lnk file
and Windows Terminal. Since no AUMID was associated with the .exe, the
OS automatically creates one for us. However, #20018 added an AUMID for
unpackaged scenarios, so now there was a mismatch, resulting in a new
taskbar entry being created.

To fix this, we check if a .lnk points to our .exe in the taskbar.
There's 3 cases here:
1. no .lnk of interest exists --> set the AUMID normally
2. the .lnk carries our AUMID --> set the AUMID normally
3. the .lnk doesn't have an AUMID (aka uses the auto-resolved one) -->
- for this launch: don't set the AUMID so that we both use the
auto-resolved one
- on next launch: set the AUMID on the .lnk and process so that they all
agree

## Validation Steps Performed
In unpackaged folder, move WindowsTerminal.exe to the taskbar (creates
.lnk)...
 Double-click the .exe --> Same taskbar entry is used
 Double-click the .exe _again_ --> second window goes to same taskbar
entry

The first window doesn't have to close for this to work. It just * works
*!

Bug introduced in #20018 
Closes #20053
2026-05-01 16:56:19 -05:00
Carlos Zamora
e4e3f08efc Add toast notification infrastructure (#20010)
## Summary of the Pull Request
Adds the infrastructure for toast notifications. Breakdown:
- `DesktopNotification`:
- `DesktopNotificationArgs` includes the struct to group all
notification-related data together.
   - `SendNotification()` actually sends it
- `AppCommandlineArgs.cpp`: added a check for the `--from-toast` no-op
sentinel; ensures no new window is created
- Most of the other changes are just bubbling up the notification from
the `TerminalPaneContent` to `TerminalPage`
- `TabManagement.cpp`: `_SendDesktopNotification()` does the final
packaging of the notification before calling the `DesktopNotification`
API

This supports finding the right tab when it's been reordered or even
moved to a new window!
This also has expanded to support finding the right pane, which is
resilient to pane swaps/closing too. When the pane can't be found, we
just fallback to the tab.
If the pane is already focused, we don't send a notification.

This simply adds the infrastructure! Looks like nothing can actually
take advantage of it yet, but it's been tested with the changes in
#20011.

Heavily based on #19935
Co-authored by @zadjii-msft
2026-04-29 17:24:45 -07:00
Dustin L. Howett
84e807cbeb appx: add appLicensing to Preview and Stable manifests (#20163)
This should prevent an outage like the one from #19764
2026-04-29 17:04:16 -05:00
Carlos Zamora
115ec2cbb9 Fix rounding error for word selection (#20084)
## Summary of the Pull Request
Dustin reported this bug to me. Thankfully it was an easy fix.

## References and Relevant Issues
Bug from implementing #5099

## Validation Steps Performed
Double-click ____ of right-most cell of a word selects the current word
 right-half
 left-half
2026-04-29 17:01:43 -05:00
Carlos Zamora
3362651659 Tab menu: show "restart" + maintain items' enable state (#19972)
## Summary of the Pull Request
Changes how/when we display the "restart connection" item in the tab's
context menu. Now, we always display it, but it's disabled if we're not
in a terminal tab.

Applies similar enable/disable logic to the rest of the menu items.
Previous to this, they just wouldn't do anything (which is fair, they
didn't make any sense).

## Validation Steps Performed
Check tab's menu in following scenarios:
 terminal pane
 settings tab
 snippets pane

Closes #18891
2026-04-29 18:54:43 +00:00
Carlos Zamora
c72600dd4f Add more settings model unit tests (#20117)
## Summary of the Pull Request
Adds tests to `UnitTests_SettingsModel` to improve coverage. Tests
include:
- `SettingInheritanceFallback`: Settings inherit from user defaults;
unset settings fall back to built-in defaults
- `ClearSettingRestoresInheritance`: `ClearXxx()` removes the value at
the current layer, causing fallback to the parent
- `HasSettingAtSpecificLayer`: `HasXxx() `distinguishes explicitly set
values from inherited ones
- `ModifyProfileSettingAndRoundtrip`: Change a profile setting via
setter and `ToJson()` reflects it
- `ModifyGlobalSettingAndRoundtrip`: Change global settings via setter
and `ToJson()` reflects them
- `ModifyColorSchemeAndRoundtrip`: Change a color scheme property and
the serialized JSON reflects it
- `FixupUserSettingsDetectsChanges`: A clean roundtrip produces
idempotent FixupUserSettings() (returns false)
- `FixupCommandlinePatching`: 4 sub-cases: CMD/PowerShell short names
get patched to full paths, no-op when already clean, custom profiles are
untouched

This also updates `TestCloneInheritanceTree` to verify that `HasXxx()`
and settters that modify the clone don't modify the original.

This is being done in preparation for auto-save to help ensure we don't
have any regressions.

## Validation Steps Performed
 Tests pass
 Manually reviewed the new tests, they make sense and do add value
(though some are less valuable than others, admittedly)
 Sent Copilot on a quest to ensure we're not adding redundant tests. It
did catch a few and remove them fwiw.
2026-04-29 10:16:30 -07:00
Windows Console Service Bot
eeb9f7a805 Localization Updates - minor wording changes after spell check - 04/24/2026 03:05:26 (#20140)
Co-authored-by: Console Service Bot <consvc@microsoft.com>
2026-04-28 03:41:39 +00:00
Josh Soref
c17029a7e9 Update dictionaries (#20148)
Follow up to #20141
2026-04-26 20:43:00 -05:00
Josh Soref
c62bb193d3 Refresh check-spelling metadata for v0.0.26 (#20141)
This is a refresh of spell-check-this, more or less as of
e089393b4e.

## References and Relevant Issues

A number of changes take advantage of features from
http://github.com/check-spelling/check-spelling/releases/v0.0.26

1.
[`load-config-from`](https://docs.check-spelling.dev/Configuration#load-config-from)
will allow future PRs to switch cleanly w/o the mess that this PR has --
once this merges, the `config.json` file will be used for the three
dictionary configuration elements instead of the ones in the workflow.
2. `contents: read` is no longer needed by the comment jobs as the data
is provided by the main job

Contains fixes for the following specific issues:
`without`, `with`, `with the`, `with the window`, `will be`,
`whether or not`, `where the`, `using`, `uppercase or lowercase`,
`unit testing`, `to`, `to which...`, `to which`,
`to which the view refers`, `to which the pane was moved`,
`to run a command/switch to a tab/...`,
`to retrieve the user selected command`, `time,`, `the...that the`,
`the session's initial directory`, `that`, `that will ask`, `that the`,
`that opened the first flyout`, `same as terminal,`, `results,`,
`queue,`, `please`, `pane,`, `out-of-date`, `our`, `one`, `on-screen`,
`often`, `off-screen`, `of a`, `little-endian`, `left over`,
`includes, at a minimum,`, `know of`, `its`,
`if, after the calculation,`, `if`, `if we have an`, `if dragging`,
`if commands`, `guard,`, `given process information in a list`,
`from which`, `from creating`, `for which...`, `for the axis`,
`for initializing the buffer`, `containing the cursor`, `console-wait`,
`change`, `bytes`, `be`, `baseline,`, `aumid`, `at`, `ask me *again*`,
`an`, `also need to`, `again`, `add`, `add event`, `about spelunking`,
(rewrite `Appearances::_UpdateWithNewViewModel` comment), `'a'`, and ` (`

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2026-04-24 22:50:42 +00:00
Dustin L. Howett
0a6c3d71fb build: Add a 1ES Pipeline Templates version of Canary (#20127)
This pipeline runs on our agents, rather than OneBranch's, and doesn't
use all of the OneBranch machinery--which is only required for producing
a vpack that we check into Windows. Since Canary will never be a vpack,
we don't need to worry.

It runs at about twice the speed _and_ we control the build images!

This pull request also adds support for the "Terrapin Retrieval Tool,"
which will allow us to move away from having vcpkg contact remote
servers directly to download source code (and which may become mandatory
even in our OneBranch pipelines.)
2026-04-24 15:39:27 -05:00
Dustin L. Howett
17e6126597 spelling: move to v0.0.26 (#20099) 2026-04-23 19:37:41 +02:00
jason
7a83c0f167 Fix Korean IME overlay hiding characters to the right of cursor (#20041)
This commit fixes a regression in v1.24, where composing Korean text
in-between existing characters causes text to the right to be hidden.
This is problematic for the Korean IME, because it commonly inserts
the composed syllable between existing characters.

The fix compresses (removes/absorbs) available whitespace to the right
of the composition to make space for any existing text. This means
that a composition now virtually acts in insert mode.

Closes #20040
Refs #19738
Refs #20039

## Validation Steps Performed

1. Korean IME: compose `ㄷ` between `가` and `나` → display shows `가ㄷ나`,
`나` visible.
2. TUI box (vim prompt with padding): compose inside padded text box →
border preserved in place.
3. Composition at end of line (no chars to right): unaffected.
4. English and other IME input: not affected (no active composition
row).

Co-authored-by: jason <drvoss@users.noreply.github.com>
Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
2026-04-16 19:12:19 -05:00
Carlos Zamora
b2666fb346 Fix local tests (#20120)
## Summary of the Pull Request
Fixes TabTests.cpp. Changes include:
- add `"closeOnExit": "never"` to some tests to avoid the race condition
discussed in #14623. It keeps the tabs/panes around so that we can
actually test them.
- removes the `assert(false)` in `TermControl::MinimumSize()`. I've been
hitting this assert in dev builds _every time_ I split a pane. I think
it isn't adding value, but if we want to investigate it further, we can.
- update MRU tests to not use the command palette (aka tab switcher) UI.
The UI requires you to hold a modifier key down to keep it displayed.
That isn't something we can simulate. Instead we just use the relevant
APIs to simulate switching tabs. This is ok because the `MRU` list is
still updated, so we're still able to validate that we're updating it
properly.
- Add `Tab[idx]` and `MRU[idx]` notation to MRU tests to make them
easier to follow

## Validation Steps Performed
 local tests pass

Closes #19610
Closes #14623
2026-04-15 22:24:13 +00:00
Carlos Zamora
8f4fdf9751 Normalize commandline in media resource tests (#20118)
## Summary of the Pull Request
Some of the Media Resource tests were failing on my machine. Turns out
that it's because my machine uses `C:\WINDOWS` instead of `C:\Windows`.

This PR fixes those tests by calling `Profile::NormalizeCommandline()`
on a few impacted strings. This also makes them loaded after enabling
filesystem redirection in `TEST_CLASS_SETUP` so that we resolve to the
correct path expected by x86.

Admittedly, I'm not the biggest fan of using that to fix the tests, but
it's better than the alternative which is a case-insensitive string
comparison. Also, the tests are testing fallback behavior, so this
doesn't really impact that. It just makes the tests more consistently
reliable.

This also removes the unused `pingCommandline` variable.

## Validation Steps Performed
 Tests pass
2026-04-15 19:13:41 +00:00
Windows Console Service Bot
33a80191c1 Localization Updates - URL dialog and PathTranslation - 04/11/2026 (#20096)
Co-authored-by: Console Service Bot <consvc@microsoft.com>
2026-04-15 14:09:19 -05:00
Dustin L. Howett
84ae7adec6 OS PR 14890400: fix defects caught with strict compiler switches (#20100)
Related work items: MSFT-53015560

Co-authored-by: Sudhakar Prabhu <sprabhu@microsoft.com>
2026-04-10 11:41:03 -07:00
Dustin L. Howett
a6ebdd3d4a render: check the thread exit condition after every long operation (#20097)
We have received an internal report that teardown on OneCore is still
hanging. It looks like there's a chance that `TriggerTeardown` is called
during `PaintFrame`, which may result in `_threadShouldKeepRunning`
getting set to `false` (TriggerTeardown) and `_redraw` being set to
`false` as well (PaintFrame). The thread will wait forever on `_redraw`
to be signalled, which it never will, because `TriggerTeardown` is
waiting for the thread to exit.

That is:

```
Render Thread      | ConIoSrv Thread
------------------------------------
Check _enabled     |
Wait on _redraw    |
Check _keepRunning | TriggerTeardown
Paint              |   _keepRunning = false
                   |   _redraw = true
    _redraw = false|   Signal _enabled
Paint Completes    |   Wait on thread
Check _enabled     |
Wait on _redraw    |
**DEADLOCK**       | **DEADLOCK**
                   v
```

This may not be an ideal fix, but at least it checks
`_threadShouldKeepRunning` after every "long" operation (waiting and
painting) now.
2026-04-09 16:34:09 -05:00
Dustin L. Howett
031998bfc3 Track the cursor dirty flag in the correct buffer (#20095)
Failure to do so will result in every console API requiring a cursor
update stalling for 500ms because we sent the update to the wrong
buffer.

Closes #20092
2026-04-08 22:08:28 +00:00
Dustin L. Howett
41e08a68bd Path translation setting: use 🡒 instead of -> (#20088)
It looks better, as decided by committee.
2026-04-07 16:38:51 -05:00
Dustin L. Howett
81170aff78 Display a warning dialog for unsafe URLs (#20065)
We are getting a sufficient number of LLM-generated security reports
telling us that Ctrl+click and a tooltip are insufficient protection
from users clicking on links to dangerous things.

This commit displays a warning that prevents users from blindly clicking
on dangerous things.

Dangerous things include:
- any non-http and non-https and non-file URLs
- any file URLs that point to something understandable as a "program"
(so, something which resides in `PATHEXT`.)

In doing this, I learned that `til::ends_with_insensitive_ascii` was
broken.

I also learned that ContentDialogs summoned by any event handler out of
TermControl::Pointer* would lose focus immediately. It turns out that in
the absolute earliest days of Terminal, when we first created the
UserControl that became TermControl, we added our Tapped event handler.

It unconditionally focused the control.

Since `Tapped` is a higher-level event handler than `PointerPressed`, it
was firing after the gesture that opened the content dialog and stealing
focus back.

I'm fairly certain we don't need it.

Refs #7562
2026-04-07 11:23:15 -05:00
Windows Console Service Bot
c90ace8326 Localization Updates - drag drop delimiter - 04/07/2026 03:05:15 (#20042)
Co-authored-by: Console Service Bot <consvc@microsoft.com>
2026-04-07 09:59:50 -05:00
Dustin L. Howett
fd30d00304 Draft-TerminalReleases: add nuget package support, remove asset hashes (#20061) 2026-04-06 17:34:28 -05:00
Dustin L. Howett
c334f91f80 Move PointerId, focus and in-bounds handling down into Interactivity (#20017)
These do not notionally belong to TermControl; as we prepare to move
automatic scrolling down into the Interactivity layer (for
WpfTerminalControl to depend on,) we're going to need to track these in
Interactivity too.

This also converts the arguments from the winrt-specific
Foundation::Point to Core::Point, and simplifies some of the signatures
to no longer pass things we do not need to pass.

Right now, this should result in no functional change.

Some of the tests are sensitive to the fact that we never loaded
`SPI_GETWHEELSCROLLLINES`
and instead defaulted to `1`. They've been hammered back into shape.
2026-03-31 16:38:32 -07:00
jason
14f4271954 Fix Korean IME arrow key inserting character at wrong position (#20039)
Fix a regression introduced in v1.24 where pressing an arrow key during
Korean IME composition caused the committed character to be inserted at
the wrong cursor position.

Before #19738, the Korean IME activated through IMM32 (excluded from TSF
by `TF_TMAE_UIELEMENTENABLEDONLY`) and was not affected by
`TermControl::_KeyHandler` forwarding keys to the PTY during
composition. After #19738, the Korean IME activates through TSF, making
a missing composition guard in `_KeyHandler` visible as a bug.

The sequence of events that causes the bug:

1. User presses Left arrow during active Korean IME composition (e.g.
composing `가`).
2. `_KeyHandler` calls `_TrySendKeyEvent(VK_LEFT)` which enqueues
`\x1b[D` to the PTY input queue. The cursor moves.
3. TSF processes the key. The Korean IME sees the arrow and ends the
composition.
4. `OnEndComposition` schedules `_doCompositionUpdate` with
`TF_ES_ASYNC`.
5. The async session fires, reads finalized text `가`, calls
`HandleOutput("가")`.
6. PTY processes `[\x1b[D, "가"]`: cursor moves left first, then `가` is
inserted at the wrong (already-moved) position.

The fix adds a guard before `_TrySendKeyEvent`, which mirrors the
existing behavior in conhost (windowio.cpp). When TSF has an active
composition, key events are not converted into input. The Korean IME
re-injects navigation and confirmation keys after the composition ends,
at which point `HasActiveComposition()` returns false and they are
forwarded normally.

**Historical note:** This guard was not needed before PR #17067 (v1.22)
because the old implementation used WinRT `CoreTextServices` via XAML
(`TSFInputControl.xaml`). The XAML framework intercepted composition key
events before `_KeyHandler`. The new custom Win32 TSF context in #17067
no longer does this. The bug was latent from v1.22 but only became
visible for Korean in v1.24 when #19738 removed
`TF_TMAE_UIELEMENTENABLEDONLY`.

## Validation Steps Performed

1. Open Windows Terminal with Korean IME (Dubeolsik layout).
2. Type `rk` to begin composing `가` (composition active, syllable not
yet committed).
3. Press the Left arrow key.
4. Before fix: `가` is inserted one cell to the left of the intended
position.
5. After fix: `가` is inserted at the correct position, then cursor moves
left.

Also verified:
- Normal Korean text input (typing without arrow keys) still works
correctly.
- Arrow key navigation when no composition is active still works
correctly.
- English and other IME input is not affected.

Closes #20038
Refs #19738
2026-03-31 22:37:15 +00:00
Carlos Zamora
3104c8feb2 Fix selection markers appearing on scroll (#20045)
## Summary of the Pull Request
Updates the scroll handler to check the selection mode before updating
the markers.

Introduced in #19974 

## Validation Steps Performed
`ls` --> create selection --> scroll away and back
 keyboard selection: markers are present both times
 mouse selection: markers are missing both times
2026-03-31 22:29:34 +00:00
Dustin L. Howett
01f8a4031d conpty: remove accidental bool; use BOOL instead (#20035)
Closes #19102
2026-03-31 18:58:10 +02:00
Dustin L. Howett
2870a702f4 Reinstate the (apparently) load-bearing empty bracketed paste (#20037)
Some applications have come to rely on an "empty" bracketed paste packet
to indicate that the clipboard was _requested,_ but not sent. Some
agentic CLI tools use this to guess whether the clipboard contained e.g.
an image or otherwise unserializable data.

Apparently, gnome-terminal and VS Code do this; others as well (I tested
xterm, konsole, gnome-terminal and I can't remember which ones did and
which ones did not.)

Refs #19517
2026-03-30 19:00:52 -05:00
Carlos Zamora
ec939aabda Update 'restart connection' action to reset internal state (#19971)
## Summary of the Pull Request
I was becoming frustrated with getting in a state where a CLI app (i.e.
Copilot CLI) enters some VT state (like mouse mode) then doesn't unset
it when it accidentally exits. I normally use "Restart connection" to
keep the buffer and connect again. Problem is, "restart connection"
didn't actually reset the internal state! So I would type and get a
bunch of lingering VT escape sequences. This bug is tracked over in
#18425 in a more generic way.

This fixes that bug by doing the following:
- update `ITermDispatch::HardReset()` -->`HardReset(bool erase)`
   - `erase=true` does what `HardReset()` already did
- `erase=false` skips over clearing the screen and resetting the cursor
position
- expose `HardReset(false)` as `HardResetWithoutErase()` by piping it up
through `Terminal` --> `ControlCore` --> `TermControl`
-  update the restart connection handler
- `TerminalPage::_restartPaneConnection()` now calls
`HardResetWithoutErase()` before setting the new connection
- this is also the same route for the "Enter to restart connection"
scenario (text displayed when connection ends)

Relevant notes from PR discussion:
- `PSEUDOCONSOLE_INHERIT_CURSOR` is passed into the new connection via
`_restartPaneConnection()` --> `_duplicateConnectionForRestart()` -->
`_CreateConnectionFromSettings(profile,
*controlSettings.DefaultSettings(), true)`

## Validation Steps Performed
- Used this to enter mouse tracking mode: `Write-Host -NoNewline
"`e[?1003h`e[?1006h"`
- mouse selection doesn't work as usual (expected)
- invoke "restart connection" action
- mouse selection works as usual

Closes #18425
2026-03-30 18:25:12 -05:00
gcrtnst
be5dcf8e7a Fix MSB4019 error in ConPTY nupkg (#20029)
This commit fixes the following error that occurs when attempting to use the
`Microsoft.Windows.Console.ConPTY` nupkg in a Visual C++ project:

    MSB4019: The imported project "C:\Microsoft.Windows.Console.ConPTY.props" was not found.

Based on the list of reserved and well-known properties, the property
`MSBuildThisProjectDirectory` does not appear to exist.  This PR
replaces it with the correct property, `MSBuildThisFileDirectory`.
2026-03-30 21:54:39 +00:00
Leonard Hecker
4ce79d7289 Implement OSC 7 for setting the CWD (#20019)
This adds support for OSC 7 which is the same as OSC 9;9 but using
file URIs. As per the previous discussion in #8214, the problem is
that WSL shells emit URIs that can't work because the hostname in
the URI translates to an UNC path with an non-existing hostname.
In my opinion this doesn't deter the fact though that OSC 7 works
just fine for a native Windows application.

In the future we should consider trying to detect WSL file URIs
and translating it to the `--cd` argument for `wsl.exe`.

All of the heavy lifting for parsing the URI is done by 
`PathCreateFromUrlW`. It just had to be plugged into the OSC 9;9 code.

Closes #3158

## Validation Steps Performed
* Launch fish-shell in WSL
* Duplicate tab works 
* (And because it doesn't work without using
  `IsValidDirectory` I know that OSC 7 works )
2026-03-30 18:10:26 +00:00
Vallabh Mahajan
69e4590bc5 Add setting for customizable delimiter for file drag-and-drop (#19799)
## Summary of the Pull Request
This PR introduces a new profile setting, `dragDropDelimiter`, which
allows users to configure the string separator used when dragging and
dropping multiple files into the terminal. The default behavior remains
a single space (`" "`) for backward compatibility.

## References and Relevant Issues
* Closes #19565

## Detailed Description of the Pull Request / Additional comments
**Implementation Details:**
* **Settings:** Added `DragDropDelimiter` to `MTSMSettings.h` and
`Profile.idl`.
* **Control:** Wired the setting through `ControlProperties.h` so the
terminal logic can see it.
* **Logic:** Updated `TermControl::OnDrop` to use the new delimiter when
joining paths.
* **UI:** Added the text box in the Advanced Settings page and updated
the ViewModel.

## Validation Steps Performed
* **Manual Verification:**
    * Verified default behavior (space separator) works as before.
* Configured `dragDropDelimiter` to `", "`, `";"`, and custom strings in
`settings.json` and from settings UI.
    * Confirmed dropped files are joined correctly.
* **Build:** Validated that the solution builds cleanly.

## Notes for Reviewers
1. **Delimiter Length:** Currently, there is no limit on the maximum
length of the delimiter string. Let me know if this should be changed.
3.  **Localization:** I changed only `Resources/en-US` file.
4. **ViewModel:** In `ProfileViewModel.cpp`, I added the `else if` block
for the new setting, but left it empty because no other UI logic
currently depends on it.

## PR Checklist
- [x] Closes #19565
- [ ] Documentation updated
- [x] Schema updated (if necessary)
2026-03-30 10:38:01 -07:00
Ethan Balakumar
a1a43a4ff5 Terminal receives focus on drag n drop (#20003)
### Summary
Updates terminal to gain foreground focus when a user drags and drops a
file into the terminal.

### Changes
Updates the `DragDropHandler` to call `SetForegroundWindow`.

### Validation
* Built and deployed locally
* Manually verified terminal gains focus when dragging and dropping

Closes #19934
2026-03-27 21:48:01 +00:00
Sagar
3ab2acc2ad Fix Settings tab color mismatch with Settings page background (#19999)
## Summary
The Settings tab color (`SettingsUiTabBrush`) was out of sync with the
Settings page background (`SettingsPageBackground`), causing a visible
mismatch - the tab appeared black while the page was dark gray.

## Changes
Aligned `SettingsUiTabBrush` in `App.xaml` to match
`SettingsPageBackground` from `MainPage.xaml`:

## Validation
- Built and deployed locally as Windows Terminal Dev
- Verified Settings tab and page backgrounds match in Dark and Light
themes
- No impact on other tab colors or theming

Closes #19873
Co-authored-by: Sagar Bhure <sagarbhure@microsoft.com>
2026-03-27 21:42:50 +00:00
Carlos Zamora
eea035cb8e Set AppUserModelID for unpackaged (#20018)
## Summary of the Pull Request
Does what it says on the tin. Sets the AUMID to
`WindowsTerminal.<hash>` with a slightly different prefix
based on the branding. The hash is based on the full process image name.

Extracted from #20013
2026-03-27 18:52:32 +00:00
dagecko
a7a928cfc9 actions: pin the hash of the check-spelling action (#20022)
In theory, somebody could compromise jsoref and push a new `v0.0.25` tag. As if.
2026-03-26 15:53:26 +00:00
Leonard Hecker
da0446a7d1 Send a CPR request on every unknown sequence (#20009)
This PR is 90% wiring up OOP interfaces.

Closes #19926

## Validation Steps Performed
* Run `github.com/xtermjs/vtc`
* Observed `UnknownSequence` calls under a debugger
2026-03-24 23:00:13 +00:00
Theodore Tsirpanis
e0400150d0 Use vs-pwsh icons if applicable. (#19990)
## Summary of the Pull Request
This PR updates `VsDevShellGenerator` to use the `vs-pwsh` icon in
generated profiles, if modern PowerShell has been detected.

## References and Relevant Issues
The icons were added in #17706, but are not used anywhere.

## Detailed Description of the Pull Request / Additional comments
* Updated `VsDevShellGenerator::GetProfileCommandLine` to accept a
`bool& isPwsh` parameter, which is set to whether the generated profile
command line is using modern PowerShell. This value gets passed to
`VsDevShellGenerator::GetProfileIconPath`'s new parameter, which
determines whether to return the icon for `powershell` or `pwsh`.
2026-03-24 18:46:16 +00:00
Carlos Zamora
c562dad15d Fix search dropdown theming (#19987)
## Summary of the Pull Request
Popups are in their own separate tree, so we had to find it and set the
theme ourselves.

## Validation Steps Performed
Prereq: Windows theme = light + terminal theme = dark
 settings search dropdown is dark theme

Closes #19927
2026-03-23 11:05:02 -07:00
Leonard Hecker
0f5d883c59 Make disabling the Kitty Keyboard Protocol possible (#19995)
Avoid translating W32IM sequences to KKP.

Closes #19977

## Validation Steps Performed
* Use French Bepo keyboard layout
* Disable KKP
* Use fish shell
* `AltGr+Y` produces `{` 
2026-03-19 21:42:15 +01:00
Sagar
ad7b34e55f Fix copyOnSelect right-click overwriting clipboard with stale selection (#19943)
## Summary of the Pull Request
Fix `copyOnSelect` right-click paste overwriting the clipboard with a
stale selection instead of pasting the current clipboard contents.

## Detailed Description of the Pull Request / Additional comments
When `copyOnSelect` is enabled, the selected text is already copied to
the clipboard on left mouse button release in `PointerReleased`. The
selection is intentionally left visible as a visual reference (the
`_selectionNeedsToBeCopied` flag is set to `false` to track that the
copy already happened).

However, the right-click handler in `PointerPressed` unconditionally
called `CopySelectionToClipboard()` before pasting, ignoring both the
`copyOnSelect` setting and the `_selectionNeedsToBeCopied` flag. This
caused any still-visible selection to be re-copied to the clipboard,
overwriting whatever the user may have copied from another application
(or another terminal tab) in the meantime.

This change splits the right-click behavior based on the `copyOnSelect`
setting:
- **`copyOnSelect: true`** — Skip the redundant copy, clear the
selection, and paste directly. The text was already copied on mouse-up.
- **`copyOnSelect: false`** — Preserve existing behavior: copy the
selection (if any), clear it, and paste only if there was no selection
to copy.

## Validation Steps Performed
1. Set `"copyOnSelect": true` in `settings.json`.
2. Selected text in a terminal pane - verified it was copied to
clipboard on mouse-up.
3. Switched to Notepad, copied different text ("NEW TEXT").
4. Switched back to Terminal (selection still visible), right-clicked —
verified "NEW TEXT" was pasted, not the old selection.
5. Verified right-click with no active selection still pastes clipboard
contents.
6. Verified right-click immediately after selecting (no app switch)
pastes the just-selected text.
7. Set `"copyOnSelect": false` — verified right-click still copies
selection first, then pastes only when no selection exists (original
behavior unchanged).
8. Verified tab-switching with an active selection does not cause stale
clipboard overwrites on right-click.

## PR Checklist
Closes #14465 (dupe of #19942)

---------

Co-authored-by: Sagar Bhure <sagarbhure@microsoft.com>
2026-03-19 11:29:01 -07:00
Leonard Hecker
ddf514e99e Fix a deadlock during cooked reads (#19994)
Closes #19922

## Validation Steps Performed
* The repro now works as expected 
  (`CreatePseudoConsole({1,20})` + `WriteFile("キ")`)
2026-03-19 17:31:04 +00:00
Dustin L. Howett
d4425a397c conhost: atlas: prevent D3DCompile/hot shader reload in CHK builds (#19924)
Whoops. `chk` builds are failing because Atlas tries to do hot shader
reload in `DEBUG` builds.

That works in our public repo, but here there is not usually going to be
access to the source code.

Reviewed-by: Leonard Hecker <lhecker@microsoft.com>
2026-03-18 17:34:33 -07:00
Dustin L. Howett
0e19570468 Only run the render thread for headed console apps (#19986)
This saves us all of the cost of preparing the renderer when we're not
going to use it.

Related to #19984
2026-03-18 17:53:05 -05:00
Dustin L. Howett
f8b4e19e51 avoid committing rows just to figure out rendition, blink and cursor (#19984)
We have been looking at a set of conhost crashes due to low-memory
conditions. I've observed that they all happen during the first pass of
rendering, before there's even an engine set up, when we try to estimate
whether there are any blink attributes. I also found that we'll commit
the buffer to check the cursor's double-width status and whether it's on
a double-width-rendition line.

Uncommitted rows _never_ contain a blinker, are never double-width and
never contain DBCS.

We can't necessarily avoid committing an empty buffer _forever,_ but
this at least moves the first commit until after the renderer truly
starts.

This prevents us from committing an empty buffer for headless console
apps (!)
2026-03-18 17:52:59 -05:00
Carlos Zamora
2e33056fd8 Improve UX for selection during VTMM (#19973)
Selection in VT mouse mode has been feeling a little weird. I've made a
few changes in this space to improve the overall experience when in vt
mouse mode:
- don't round selection positions: this means that you now highlight the
cell you're on if you're going right, and the adjacent cell if you're
going left
- fix drag-left excluding the current cell
- #9608: shift+click now clears any existing selection instead of
extending it. This feels more intuitive since Shift already works as the
override modifier

Somewhat related to #18106 

## Validation
 alt selections feel consistent
 selecting in VTMM feels accurate (selects the cell we started on)
 creating new selections (aka clearing old selection) in VTMM feels
intuitive (forwards and backwards)

Closes #9608
2026-03-17 16:46:36 -05:00
Carlos Zamora
14ee19fc27 Fix selection markers disappearing after scrolling out of view (#19974)
## Summary of the Pull Request
Pretty straightforward

## Validation Steps Performed
 Selection markers are present after scrolling them out of view and
scrolling back

Closes #17135
2026-03-16 17:21:39 -05:00
Dustin L. Howett
987fce20a1 OS-15022958: conhost: onboard our RI-TPs for other internal Windows editions (#19975)
This required the following changes:
- Delayloading ICU in all of our tests, and skipping tests where it
could not be loaded
- Adding a new test group which skips the PolicyTests, which cannot be
run on some editions which have no app platform.

In addition, instead of onboarding new failing test passes, this pull
request finally repairs the broken ConPTY tests (which diverged from the
OSS implementation and had to be re-en-verged)

Closes MSFT-61409507
Reflected from OS PR !15022958
2026-03-14 11:33:04 -05:00
Carlos Zamora
040c730a44 Simplify word expansion functions (#19882)
## Summary of the Pull Request
Simplifies the word expansion functions in TextBuffer by removing the
following functions:
- `GetWordStart2()`
- `GetWordEnd2()`
- `MoveToNextWord()`
- `MoveToPreviousWord()`
-  `_GetWordStartForAccessibility()`
-  `_GetWordStartForSelection()`
- `_GetWordEndForAccessibility()`
- `_GetWordEndForSelection()`

In favor of a simple:
- `GetWordStart()`
- `GetWordEnd()`
- _GetDelimiterClassRunStart()`
- `_GetDelimiterClassRunEnd()`

Tests were used to help ensure a regression doesn't occur. That said,
there were a few modifications there too:
- Removed `MoveByWord` test
- It directly called `MoveToNextWord()` and `MoveToPreviousWord()`,
which no longer exist. These were helper functions for
`UiaTextRangeBase`, and any special logic has been moved into
`_moveEndpointByUnitWord` using the unified
`GetWordStart()`/`GetWordEnd()` APIs.
- The tested behavior is still covered by `MoveToPreviousWord`,
`MovementAtExclusiveEnd`, and the generated word movement tests.
- updated `GetWordBoundaries` tests
- Inclusive --> exclusive end positions for `GetWordEnd()`: The old
`_GetWordEndForSelection()` returned inclusive end positions, whereas
the new `GetWordEnd()` returns exclusive end positions. This is what
`GetWordEnd2()` already used, so every old expected value shifted +1 in
the x direction (or to {RightExclusive, y} at row boundaries) to account
for that.
- `ControlChar` wrap-crossing behavior: The old
`_GetWordStartForSelection()` had a special check at the left boundary
that prevented whitespace runs from crossing wrapped row boundaries. The
new `_GetDelimiterClassRunStart()` doesn't have this special case (it
treats ControlChar the same as other delimiter classes when the row was
wrap-forced). This changed one test case: `GetWordStart({1, 4})` in
selection mode went from `{0, 4}` to `{6, 3}` (the whitespace run now
crosses the wrap boundary to row 3). This matches the behavior
TerminalSelection was already getting from `GetWordStart2()`.

## Validation Steps Performed
Tests passed:
 Conhost.Interactivity.Win32.Unit.Tests.dll
 UnitTests_TerminalCore\Terminal.Core.Unit.Tests.dll

Word navigation feels good for...
 Narrator
 NVDA
 Mouse selection
 Mark mode

Closes #4423
2026-03-13 21:18:04 +00:00
Dustin L. Howett
6d7fac999a Suppress the invalid media error in Stable (#19969)
It's creating a lot of noise for folks, and it is not particularly
_helpful_ since it does not specify a location or even name which
resource failed to load or parse.

On stable, let's just silently ignore them.

Refs #19964
2026-03-12 17:07:18 -05:00
Dustin L. Howett
e6ea8ace6d conhost: Unlock the console while tearing down during coniosrv focus evt (#19967)
With the rendering thread changes in #18632 and #19330, we strengthened
a requirement that render shutdown be done outside of the console lock.
This works on all platforms except OneCore, where ConIoSrv manages the
focus of multiple console windows and we need to explicitly order the
handling of tearing down and relinquishing device resources.

The old code (before #18632) used to wait for a whole second before
giving up.

Instead, let's just unlock the console to let the final frame drain out.

I created a synthetic repro: start two cmd sessions with a lot of
rendering load (`cmdd start cmd /c dir /s c:\`), and then run `cmdd date
/t` in a tight loop while tabbing between the console windows.

Before this fix, it hangs within a couple tens of date invocations. With
this fix, it does not hang at all.

Fixes MSFT-61354695
2026-03-12 12:30:45 -05:00
Leonard Hecker
36fb444d3e Improve TSF failure handling (#19965)
An internal AI correctly flagged that we aren't calling
`UnadviseSink()` in case a later `Initialize()` call fails.
We can easily fix this by calling `Uninitialize()`.
2026-03-11 21:31:04 +01:00
Artem Lytkin
e2d51636cd control: focus terminal on click-drag while search is open (#19931)
## Summary
- Fix inability to copy terminal text via Ctrl+C when the search dialog
is open
- Root cause: click-and-drag doesn't call `Focus()` because `_focused`
is already `true` (set by the search box's bubbling GotFocus)
- Fix: also focus the terminal when the search box contains keyboard
focus

## Detailed Description of the Pull Request / Additional comments
When the search dialog is open and the user click-drags in the terminal
to select text, `_PointerPressedHandler` skips
`Focus(FocusState::Pointer)` because `_focused` is `true`. The
`_focused` flag is `true` because the `SearchBoxControl` is a child of
`TermControl` in the XAML visual tree, so `TermControl`'s
`_GotFocusHandler` fires (via bubbling `GotFocus`) when the search box's
`TextBox` gains focus, setting `_focused = true`.

The fix adds a `ContainsFocus()` check so that focus is explicitly moved
to the terminal when the search box has keyboard focus. This makes
click-drag behavior consistent with tap behavior (`_TappedHandler`
already focuses unconditionally) and uses the same `ContainsFocus()`
pattern already established at lines 1569 and 2366 in the same file.

## Validation Steps Performed
- Verified click-drag + Ctrl+C copies selected text when search dialog
is open
- Verified simple click (tap) in terminal while search is open still
works
- Verified clicking in the search box retains focus in the search box
- Verified typing in search box still works when it has focus
- Verified Escape still closes the search box
- Verified Ctrl+C with no selection while search is open doesn't break
- Code formatted with clang-format

## PR Checklist
 Closes #19908
2026-03-11 18:03:21 +00:00
Dustin L. Howett
80e4b3c947 Only honor Ctrl+Z during ReadFile if the console is in PROCESSED mode (#19940)
This restores the behavior of ReadFile to that of Windows 7.

Closes #4958
2026-03-11 11:52:33 -05:00
Carlos Zamora
e2110e716c Fix memory leaks with UIA (#19950)
## Summary of the Pull Request
This includes the memory leak fixes that @lhecker and I investigated as
a part of #19710.

The `ITextRangeProvider`s (namely `UiaTextRange`s) weren't being
destroyed after they were done being used by the screen reader.

## Validation Steps Performed
In my own testing, I set a breakpoint on the destructor for
`UiaTextRangeBase`. Prior to this change, that destructor would mainly
be called when the terminal control was closed, which would result in us
leaking these objects. With this change, I've confirmed that these text
ranges are being destroyed immediately after they are done being used
(without needing to close the terminal control).

## PR Checklist
Closes #19710
2026-03-11 02:08:32 +01:00
Dustin L. Howett
9e4986edb0 README: remove the outdated roadmap link (#19932)
Historical roadmaps remain available in the `doc` directory.
2026-03-10 16:24:13 -07:00
Leonard Hecker
30b1456ffe Make TSF initialization fully fallible (#19958)
Apparently, on some (internal) variants of Windows `TF_CategoryMgr`
can exist while `TF_DisplayAttributeMgr` is absent. This is likely
a variant configuration error, but we shouldn't crash anyway.

Closes MSFT-61309810
2026-03-10 21:31:54 +01:00
Leonard Hecker
5bd9e9fd89 Always use the cls shim for cmd/pwsh (#19957)
This improves performance and avoids a memory spike on `cls`.

## Validation Steps Performed
* `cls` clears 
* RSS doesn't spike 
2026-03-10 21:31:44 +01:00
sagarbhure-dev
8cad67020f Fix GenerateSettingsIndex using element name instead of x:Name (#19945)
Use GetAttribute('x:Name') instead of .Name in GenerateSettingsIndex.ps1
to avoid PowerShell's XML integration returning the element tag name
(e.g. 'local:SettingContainer') when x:Name is absent.

Also add missing x:Name attributes to:
- Compatibility.xaml: AmbiguousWidth SettingContainer
- NewTabMenu.xaml: AddRemainingProfiles and CurrentFolderIcon containers

## Summary of the Pull Request
Fix GenerateSettingsIndex.ps1 emitting "local:SettingContainer" as the
element name in the generated index when a SettingContainer has no
x:Name attribute.

## References and Relevant Issues
Per DHowett's comment - the root cause is PowerShell's XML integration:
$element.Name returns the XML element tag name (e.g.
local:SettingContainer) when no x:Name attribute exists.

## Detailed Description of the Pull Request / Additional comments
Two changes:

- GenerateSettingsIndex.ps1: Replace $settingContainer.Name with
$settingContainer.GetAttribute("x:Name"), which correctly returns an
empty string when the attribute is absent instead of the element tag
name.

- Add missing x:Name attributes to three SettingContainer elements:
    - Compatibility.xaml: AmbiguousWidth (Globals_AmbiguousWidth)
- NewTabMenu.xaml: AddRemainingProfiles
(NewTabMenu_AddRemainingProfiles)
    - NewTabMenu.xaml: CurrentFolderIcon (NewTabMenu_CurrentFolderIcon)
- This fixes four incorrect IndexEntry lines in the generated output
that previously contained L"local:SettingContainer" as the element name.

## Validation Steps Performed
Ran GenerateSettingsIndex.ps1 before and after - confirmed the four
incorrect entries with L"local:SettingContainer" are now generated with
the correct x:Name values (or empty string where appropriate).

## PR Checklist
Closes #19929

Co-authored-by: Sagar Bhure <sagarbhure@microsoft.com>
2026-03-10 17:03:15 +00:00
Dustin L. Howett
5828fb5ce5 vpack: actually, we have to use a 3-segment version number (#19939)
Our last build failed because it tried to pass "10621.0" off as a
uint64. I didn't know it had to be a single number... so let's use the
3-component equivalent (which would have been 1.24.260303001)
2026-03-05 16:44:39 -06:00
292 changed files with 5920 additions and 2262 deletions

View File

@@ -8,7 +8,7 @@ body:
value: |
Please make sure to [search for existing issues](https://github.com/microsoft/terminal/issues) and [check the FAQ](https://github.com/microsoft/terminal/wiki/Frequently-Asked-Questions-(FAQ)) before filing a new one!
If this is an application crash, please also provide a [Feedback Hub](https://aka.ms/terminal-feedback-hub) submission link so we can find your diagnostic data on the backend. Use the category "Apps > Windows Terminal" and choose "Share My Feedback" after submission to get the link.
If this is an application crash, please provide a [Feedback Hub](https://aka.ms/terminal-feedback-hub) submission link so we can find your diagnostic data on the backend. Use the category "Apps > Windows Terminal" and choose "Share My Feedback" after submission to get the link.
- type: input
attributes:

View File

@@ -10,6 +10,7 @@ File | Purpose | Format | Info
[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[expect/*.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect)
[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice)
[config.json](config.json) | Action Configuration | JSON key (action configuration variable) value (action configuration value) | [config](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-config)
Note: you can replace any of these files with a directory by the same name (minus the suffix)
and then include multiple files inside that directory (with that suffix) to merge multiple files together.

View File

@@ -22,6 +22,7 @@ See the `README.md` in each directory for more information.
<details><summary>If the flagged items are :exploding_head: false positives</summary>
If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).
Please add a file path to the `excludes.txt` file matching the containing file.

View File

@@ -23,8 +23,10 @@ FTCS
gantt
gfm
ghe
github
godbolt
hstrings
https
hyperlinking
hyperlinks
Kbds
@@ -44,6 +46,7 @@ mru
notwrapped
NTMTo
overlined
passthrough
perlw
postmodern
Powerline
@@ -65,6 +68,7 @@ rubyw
runtimes
servicebus
slnt
ssh
stakeholders
subpage
subpages
@@ -72,10 +76,11 @@ sustainability
sxn
Tencent
toolset
Uids
ubuntu
UEFI
UIDs
uiatextrange
Uids
UIDs
und
vsdevcmd
westus

View File

@@ -1,5 +1,5 @@
# Repeated letters
\b([a-z])\g{-1}{2,}\b
\b([A-Za-z])\g{-1}{2,}\b
# marker to ignore all code on line
^.*/\* #no-spell-check-line \*/.*$
@@ -11,7 +11,7 @@
^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b
# copyright
Copyright (?:\([Cc]\)|)(?:[-\d, ]|and)+(?: [A-Z][a-z]+ [A-Z][a-z]+,?)+
Copyright (?:\([Cc]\)|©|)(?:[-\d, ]|and)+(?: [A-Z][a-z]+ [A-Z][a-z]+,?)+
# patch hunk comments
^@@ -\d+(?:,\d+|) \+\d+(?:,\d+|) @@ .*
@@ -19,10 +19,10 @@ Copyright (?:\([Cc]\)|)(?:[-\d, ]|and)+(?: [A-Z][a-z]+ [A-Z][a-z]+,?)+
index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# file permissions
['"`\s][-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s]
(?:^|['"`\s])(?!-+\s)[-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s]
# css fonts
\bfont(?:-family|):[^;}]+
\bfont(?:-family(?:[-\w+]*)|):[^;}]+
# css url wrappings
\burl\([^)]+\)
@@ -36,10 +36,10 @@ index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# data url in quotes
([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
# data url
\bdata:[-a-zA-Z=;:/0-9+]*,\S*
\bdata:[-a-zA-Z=;:/0-9+_]*,\S*
# https/http/file urls
(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/*%?=~_|!:,.;]+[-A-Za-z0-9+&@#/*%=~_|]
#(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/*%?=~_|!:,.;]+[-A-Za-z0-9+&@#/*%=~_|]
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@._]{3,}
@@ -88,6 +88,9 @@ arn:aws:[-/:\w]+
# AWS VPC
vpc-\w+
# Azure AD
\baad\.\w{48}\b
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
# YouTube url
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
@@ -169,7 +172,7 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
GHSA(?:-[0-9a-z]{4}){3}
# GitHub actions
\buses:\s+[-\w.]+/[-\w./]+@[-\w.]+
\buses:\s+(['"]?)[-\w.]+/[-\w./]+@[-\w.]+\g{-1}
# GitLab commit
\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b
@@ -238,7 +241,7 @@ accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
\bmedium\.com/@?[^/\s"]+/[-\w]+
# microsoft
\b(?:https?://|)(?:(?:(?:blogs|download\.visualstudio|docs|msdn2?|research)\.|)microsoft|blogs\.msdn)\.co(?:m|\.\w\w)/[-_a-zA-Z0-9()=./%]*
\b(?:https?://|)(?:(?:(?:blogs|download\.visualstudio|docs|msdn2?|research)\.|)microsoft|blogs\.msdn)\.co(?:m|\.\w\w)/[-_a-zA-Z0-9()=./%?#]*
# powerbi
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
# vs devops
@@ -412,7 +415,7 @@ ipfs://[0-9a-zA-Z]{3,}
\bgetopts\s+(?:"[^"]+"|'[^']+')
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\\03[1-7]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+)*m
#(?:\\(?:u00|x)1[Bb]|\\03[1-7]|\x1b|\\u\{1[Bb]\})\[(?:\d+(?:;\d+)*|)m
# URL escaped characters
%[0-9A-F][A-F](?=[A-Za-z])
@@ -430,7 +433,7 @@ sha\d+:[0-9a-f]*?[a-f]{3,}[0-9a-f]*
# sha-... -- uses a fancy capture
(\\?['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hex runs
\b[0-9a-fA-F]{16,}\b
\b(?=(?:[a-fA-F]{0,2}\d)*[a-fA-F]{3})[0-9a-fA-F]{16,}\b
# hex in url queries
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
# ssh
@@ -454,8 +457,12 @@ LS0tLS1CRUdJT.*
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|%23|&H)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
# unicode escaped characters (4)
\\u[0-9a-fA-F]{4}
# hex digits including css/html color classes
(?:[\\0][xX]|\\u\{?|[uU]\+|#x?|%23|&H)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
# integrity
integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1}
@@ -477,7 +484,7 @@ Name\[[^\]]+\]=.*
(?:(?:\b|_|(?<=[a-z]))I|(?:\b|_)(?:nsI|isA))(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
# python
\b(?i)py(?!gments|gmy|lon|ramid|ro|th)(?=[a-z]{2,})
\b(?i)py(?!gment|gmy|lon|ramid|ro|th)(?=[a-z]{2,})
# crypt
(['"])\$2[ayb]\$.{56}\g{-1}
@@ -497,12 +504,21 @@ Name\[[^\]]+\]=.*
# go.sum
\bh1:\S+
# golang print-f-style functions
#(?i)(?<=append|comma|debug|equal|err|error|exit|fatal|format|info|log|name|panic|print|skip|scan|string|trace|true|warn|warning|wrap|write)(?:f|ln)(?:[ (]|$)
# golang regular expression
#(?<!")\br".+?"
# imports
^import\s+(?:(?:static|type)\s+|)(?:[\w.]|\{\s*\w*?(?:,\s*(?:\w*|\*))+\s*\})+
^import\s+(?:(?:static|type)\s+|)(?:[\w.]|\{\s*\w*?(?:,\s*(?:\w*|\*))+\s*\})+(?:\s+from (['"]).*?\g{-1}|)
# scala modules
("[^"]+"\s*%%?\s*){2,3}"[^"]+"
# Dataframes / NumPy
\b(?:df|np)\.\w{3,}
# container images
image: [-\w./:@]+
@@ -513,7 +529,7 @@ image: [-\w./:@]+
\s*\S+/\S+\s+\S+\s+[0-9a-f]{8,}\s+\d+\s+(?:hour|day|week)s ago\s+[\d.]+[KMGT]B
# Intel intrinsics
_mm_(?!dd)\w+
_mm\d*_(?!dd)\w+
# Input to GitHub JSON
content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
@@ -532,12 +548,18 @@ content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
(?<!['"])\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)['"](?=[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
# Regular expression for word breaks
#\\b(?=[a-z]{2})
# Regular expressions for (P|p)assword
\([A-Z]\|[a-z]\)[a-z]+
# Java regular expressions
Pattern\.(?:compile|matches)\(".*"
# JavaScript regular expressions
# javascript test regex
/.{3,}/[gim]*\.test\(
# javascript exec/test regex
/.{3,}?/[gim]*\.(?:exec|test)\(
# javascript match regex
\.match\(/[^/\s"]{3,}/[gim]*\s*
# javascript match regex
@@ -564,7 +586,7 @@ perl(?:\s+-[a-zA-Z]\w*)+
regexp?\.MustCompile\((?:`[^`]*`|".*"|'.*')\)
# regex choice
\(\?:[^)]+\|[^)]+\)
#\((?=[^)]*[a-zA-Z]{3})(?:\?:|)[^)|]+(?<! )\|(?!(?:jq|xargs)\b)[^)| ][^)]*\)
# proto
^\s*(\w+)\s\g{-1} =
@@ -587,6 +609,9 @@ urn:shemas-jetbrains-com
# Debian changelog severity
[-\w]+ \(.*\) (?:\w+|baseline|unstable|experimental); urgency=(?:low|medium|high|emergency|critical)\b
# Red Hat Package management spec file dependencies
^(?:Build|)Requires: [-.\w]+
# kubernetes pod status lists
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
@@ -641,6 +666,8 @@ PrependWithABINamepsace
>[-a-zA-Z=;:/0-9+]{3,}=</
# base64 encoded content, possibly wrapped in mime
#(?:^|[\s=;:?])[-a-zA-Z=;:/0-9+]{50,}(?:[\s=;:?]|$)
# jwt
(?:\be[wy][-a-zA-Z=;:/0-9+]+\.){2}[-_\w]+
# base64 encoded json
\beyJ[-a-zA-Z=;:/0-9+]+
# base64 encoded pkcs
@@ -678,9 +705,9 @@ systemd.*?running in system mode \([-+].*\)$
# Non-English
# Even repositories expecting pure English content can unintentionally have Non-English content... People will occasionally mistakenly enter [homoglyphs](https://en.wikipedia.org/wiki/Homoglyph) which are essentially typos, and using this pattern will mean check-spelling will not complain about them.
#
# .
# If the content to be checked should be written in English and the only Non-English items will be people's names, then you can consider adding this.
#
# .
# Alternatively, if you're using check-spelling v0.0.25+, and you would like to _check_ the Non-English content for spelling errors, you can. For information on how to do so, see:
# https://docs.check-spelling.dev/Feature:-Configurable-word-characters.html#unicode
[a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
@@ -692,7 +719,7 @@ systemd.*?running in system mode \([-+].*\)$
# This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b
# latex (check-spelling >= 0.0.22)
# LaTeX
\\\w{2,}\{
# American Mathematical Society (AMS) / Doxygen
@@ -719,7 +746,6 @@ nolint:\s*[\w,]+
# cygwin paths
/cygdrive/[a-zA-Z]/(?:Program Files(?: \(.*?\)| ?)(?:/[-+.~\\/()\w ]+)*|[-+.~\\/()\w])+
# in check-spelling@v0.0.22+, printf markers aren't automatically consumed
# printf markers
#(?<!\\)\\[nrt](?=[a-z]{2,})
@@ -750,18 +776,20 @@ W/"[^"]+"
# Compiler flags (Unix, Java/Scala)
# Use if you have things like `-Pdocker` and want to treat them as `docker`
#(?:^|[\t ,>"'`=(#])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
#(?:^|[\t ,>"'`=\[(#])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (Windows / PowerShell)
# This is a subset of the more general compiler flags pattern.
# It avoids matching `-Path` to prevent it from being treated as `ath`
#(?:^|[\t ,"'`=(#])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
#(?:^|[\t ,"'`=\[(#])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
# Compiler flags (linker)
,-B
# libraries
#(?:\b|_)[Ll]ib(?:re(?=office)|)(?!era[lt]|ero|erty|rar(?:i(?:an|es)|y))(?=[a-z])
# Library prefix
# e.g., `lib`+`archive`, `lib`+`raw`, `lib`+`unwind`
# (ignores some words that happen to start with `lib`)
#(?:\b|_)[Ll]ib(?!era[lt])(?:re(?=office)|era|)(?!ero|erty|rar(?:i(?:an|es)|y))(?=[a-z])
# iSCSI iqn (approximate regex)
\biqn\.[0-9]{4}-[0-9]{2}(?:[\.-][a-z][a-z0-9]*)*\b
@@ -772,9 +800,9 @@ W/"[^"]+"
# curl arguments
\b(?:\\n|)curl(?:\.exe|)(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# set arguments
\b(?:bash|sh|set)(?:\s+[-+][abefimouxE]{1,2})*\s+[-+][abefimouxE]{3,}(?:\s+[-+][abefimouxE]+)*
\b(?:bash|(?<!\.)sh|set)(?:\s+[-+][abefimouxE]{1,2})*\s+[-+][abefimouxE]{3,}(?:\s+[-+][abefimouxE]+)*
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
\b(?:\\n|)g?tar(?:\.exe|)(?:\s-C \S+|(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
# macOS temp folders

105
.github/actions/spelling/config.json vendored Normal file
View File

@@ -0,0 +1,105 @@
{
"dictionary_source_prefixes": {
"asm": "https://raw.githubusercontent.com/check-spelling/assembly-dictionaries/20231110/",
"cspell": "https://raw.githubusercontent.com/check-spelling/cspell-dicts/v20241114/dictionaries/",
"census": "https://raw.githubusercontent.com/check-spelling-sandbox/census/dictionaries-d90e686f89dd241ad61d30f26619e54d73e73c6e/dictionaries/"
},
"extra_dictionaries": [
"cspell:software-terms/softwareTerms.txt",
"cspell:cpp/stdlib-c.txt",
"census:census-5.txt",
"cspell:cpp/stdlib-cpp.txt",
"cspell:python/python/python-lib.txt",
"cspell:php/php.txt",
"cspell:dart/dart.txt",
"cspell:css/css.txt",
"cspell:node/node.txt",
"cspell:filetypes/filetypes.txt",
"cspell:npm/npm.txt",
"cspell:java/java.txt",
"cspell:dotnet/dotnet.txt",
"cspell:fullstack/fullstack.txt",
"cspell:java/java-terms.txt",
"cspell:cpp/stdlib-cmath.txt",
"cspell:typescript/typescript.txt",
"cspell:cpp/compiler-msvc.txt",
"cspell:python/common/extra.txt",
"cspell:html/html.txt",
"cspell:golang/go.txt",
"cspell:cpp/ecosystem.txt",
"cspell:powershell/powershell.txt",
"cspell:mnemonics/mnemonics.txt",
""
],
"check_extra_dictionaries": [
"asm:amd64-isa.txt",
"asm:ia64-isa.txt",
"asm:power-isa.txt",
"cspell:ada/ada.txt",
"cspell:aws/aws.txt",
"cspell:clojure/clojure.txt",
"cspell:companies/companies.txt",
"cspell:cpp/compiler-clang-attributes.txt",
"cspell:cpp/compiler-gcc.txt",
"cspell:cpp/compiler-msvc.txt",
"cspell:cpp/ecosystem.txt",
"cspell:cpp/lang-jargon.txt",
"cspell:cpp/lang-keywords.txt",
"cspell:cpp/people.txt",
"cspell:cpp/stdlib-c.txt",
"cspell:cpp/stdlib-cerrno.txt",
"cspell:cpp/stdlib-cmath.txt",
"cspell:cpp/stdlib-cpp.txt",
"cspell:cpp/template-strings.txt",
"cspell:cryptocurrencies/cryptocurrencies.txt",
"cspell:csharp/csharp.txt",
"cspell:css/css.txt",
"cspell:dart/dart.txt",
"cspell:django/django.txt",
"cspell:django/requirements.txt",
"cspell:docker/docker-words.txt",
"cspell:dotnet/dotnet.txt",
"cspell:elixir/elixir.txt",
"cspell:filetypes/filetypes.txt",
"cspell:fonts/fonts.txt",
"cspell:fullstack/fullstack.txt",
"cspell:gaming-terms/gaming-terms.txt",
"cspell:golang/go.txt",
"cspell:haskell/haskell.txt",
"cspell:html/html.txt",
"cspell:java/java-terms.txt",
"cspell:java/java.txt",
"cspell:k8s/k8s.txt",
"cspell:latex/latex.txt",
"cspell:latex/samples/sample-words.txt",
"cspell:lisp/lisp.txt",
"cspell:lorem-ipsum/dictionary.txt",
"cspell:lua/lua.txt",
"cspell:mnemonics/mnemonics.txt",
"cspell:monkeyc/monkeyc_keywords.txt",
"cspell:node/node.txt",
"cspell:npm/npm.txt",
"cspell:php/php.txt",
"cspell:powershell/powershell.txt",
"cspell:public-licenses/generated/public-licenses.txt",
"cspell:python/additional_words.txt",
"cspell:python/common/extra.txt",
"cspell:python/python/python-lib.txt",
"cspell:python/python/python.txt",
"cspell:r/r.txt",
"cspell:redis/redis.txt",
"cspell:ruby/ruby.txt",
"cspell:rust/rust.txt",
"cspell:scala/scala.txt",
"cspell:shell/shell-all-words.txt",
"cspell:software-terms/software-terms.txt",
"cspell:software-terms/webServices.txt",
"cspell:sql/sql.txt",
"cspell:sql/tsql.txt",
"cspell:svelte/svelte.txt",
"cspell:swift/swift.txt",
"cspell:typescript/typescript.txt",
"census:census-5.txt",
""
]
}

View File

@@ -16,6 +16,7 @@
ignore$
Resources/(?!en)
[^/]\.vsdx$
-lock\.yaml$
\.a$
\.ai$
\.all-contributorsrc$
@@ -120,17 +121,19 @@ Resources/(?!en)
^src/types/ut_types/UtilsTests\.cpp$
^tools/ReleaseEngineering/ServicingPipeline\.ps1$
^XamlStyler\.json$
^\.clang-format$
^\.github/actions/spelling/
^\.github/workflows/spelling\d*\.yml$
^\.vsconfig$
^\Qbuild/config/release.gdnbaselines\E$
^\Qdep/WinAppDriver/EULA.rtf\E$
^\Qdoc/reference/windows-terminal-logo.ans\E$
^\Qsrc/cascadia/ut_app/FzfTests.cpp\E$
^\Qsrc/host/ft_host/chafa.txt\E$
^\Qsrc/host/ft_host/Host.Tests.Feature.rc\E$
^\Qsrc/host/ft_uia/run.bat\E$
^\Qsrc/host/runft.bat\E$
^\Qsrc/terminal/parser/ft_fuzzer/run.bat\E$
^\Qsrc/terminal/parser/ft_fuzzwrapper/run.bat\E$
^\Qsrc/tools/lnkd/lnkd.bat\E$
^\Qsrc/tools/pixels/pixels.bat\E$
^\Qsrc/cascadia/ut_app/FzfTests.cpp\E$

View File

@@ -5,7 +5,6 @@ BBDM
BBGGRR
CBN
cbt
Ccc
cch
efg
efgh

View File

@@ -1,13 +1,13 @@
aaaaabbb
aabbcc
ABANDONFONT
abbcc
abcc
abgr
ABANDONFONT
ABORTIFHUNG
ACCESSTOKEN
acidev
ACIOSS
ACL'd
acp
actctx
ACTCTXW
@@ -51,7 +51,6 @@ appletname
APPLMODAL
Applocal
appmodel
appshellintegration
APPWINDOW
APPXMANIFESTVERSION
APrep
@@ -60,12 +59,10 @@ ARRAYSIZE
ARROWKEYS
ASBSET
ASetting
ASingle
ASYNCDONTCARE
ASYNCWINDOWPOS
atch
ATest
atg
aumid
Authenticode
AUTOBUDDY
@@ -80,14 +77,12 @@ Autowrap
AVerify
awch
azurecr
AZZ
backgrounded
Backgrounder
backgrounding
backstory
Bazz
bbccb
BBDM
bbwe
bcount
bcx
@@ -113,7 +108,6 @@ bitmasks
BITOPERATION
BKCOLOR
BKGND
BKMK
Bksp
Blt
blu
@@ -122,7 +116,6 @@ bmi
bodgy
BOLDFONT
Borland
boutput
boxheader
BPBF
bpp
@@ -167,7 +160,7 @@ CFuzz
cgmanifest
cgscrn
chafa
changelists
changelist
CHARSETINFO
chshdng
CHT
@@ -200,6 +193,7 @@ colorizing
COLORONCOLOR
COLORREFs
colorschemes
colorspaces
colorspec
colortable
colortbl
@@ -230,14 +224,12 @@ CONKBD
conlibk
conmsgl
CONNECTINFO
connyection
CONOUT
conprops
conpropsp
conpty
conptylib
conserv
consoleaccessibility
consoleapi
CONSOLECONTROL
CONSOLEENDTASK
@@ -247,9 +239,9 @@ CONSOLEIME
CONSOLESETFOREGROUND
consoletaeftemplates
consoleuwp
Consolewait
CONSOLEWINDOWOWNER
consrv
consteval
constexprable
contentfiles
conterm
@@ -266,7 +258,6 @@ CPG
cpinfo
CPINFOEX
CPLINFO
cplusplus
CPPCORECHECK
cppcorecheckrules
cpprestsdk
@@ -277,7 +268,6 @@ CREATESTRUCT
CREATESTRUCTW
createvpack
crisman
crloew
CRTLIBS
csbi
csbiex
@@ -288,7 +278,6 @@ csrutil
CSTYLE
CSwitch
CTerminal
ctl
ctlseqs
CTRLEVENT
CTRLFREQUENCY
@@ -298,6 +287,7 @@ CTRLVOLUME
CUAS
CUF
cupxy
curated
CURRENTFONT
currentmode
CURRENTPAGE
@@ -330,7 +320,6 @@ CYVIRTUALSCREEN
CYVSCROLL
dai
DATABLOCK
DBatch
dbcs
DBCSFONT
DBGALL
@@ -339,15 +328,12 @@ DBGFONTS
DBGOUTPUT
dbh
dblclk
DBUILD
Dcd
DColor
DCOMMON
DComposition
DDESHARE
DDevice
DEADCHAR
Debian
debugtype
DECAC
DECALN
@@ -453,10 +439,8 @@ depersist
deprioritized
devicecode
Dext
DFactory
DFF
dialogbox
DINLINE
directio
DIRECTX
DISABLEDELAYEDEXPANSION
@@ -471,9 +455,9 @@ dllinit
dllmain
DLLVERSIONINFO
DLOOK
doc'd
DONTCARE
doskey
dotnet
DPG
DPIAPI
DPICHANGE
@@ -487,7 +471,6 @@ DRAWITEM
DRAWITEMSTRUCT
drcs
DROPFILES
drv
DSBCAPS
DSBLOCK
DSBPLAY
@@ -497,11 +480,8 @@ dsm
dsound
DSRCPR
DSSCL
DSwap
DTo
DTTERM
DUNICODE
DUNIT
dup'ed
dvi
dwl
@@ -530,9 +510,9 @@ ELEMENTNOTAVAILABLE
EMPTYBOX
enabledelayedexpansion
ENDCAP
endptr
ENTIREBUFFER
ENU
Enum'd
ENUMLOGFONT
ENUMLOGFONTEX
EOB
@@ -541,13 +521,13 @@ EPres
EQU
ERASEBKGND
ERRORONEXIT
espt
esrp
ESV
ETW
EUDC
eventing
evflags
evt
execd
executionengine
exemain
@@ -572,6 +552,7 @@ FGHIJ
fgidx
FGs
FILEDESCRIPTION
filehops
FILESUBTYPE
FILESYSPATH
FILEW
@@ -607,14 +588,14 @@ FORCEOFFFEEDBACK
FORCEONFEEDBACK
FRAMECHANGED
fre
Free'd
frontends
fsanitize
Fscreen
FSINFOCLASS
ftcs
fte
Ftm
Fullscreens
Fullwidth
FUNCTIONCALL
fuzzmain
fuzzmap
@@ -675,16 +656,13 @@ GETWAITTOKILLTIMEOUT
GETWHEELSCROLLCHARACTERS
GETWHEELSCROLLCHARS
GETWHEELSCROLLLINES
Gfun
gfx
gfycat
GGI
GHgh
GHIJK
GHIJKL
gitcheckin
gitfilters
gitlab
gle
GLOBALFOCUS
GLYPHENTRY
@@ -692,13 +670,13 @@ GMEM
Goldmine
gonce
goutput
GPUs
GREENSCROLL
Grehan
Greyscale
gridline
gset
gsl
Guake
guc
GUIDATOM
GValue
@@ -720,7 +698,6 @@ hbr
hbrush
HCmd
hdc
hdr
HDROP
hdrstop
HEIGHTSCROLL
@@ -785,7 +762,6 @@ ICONWARNING
IDCANCEL
IDD
IDISHWND
idl
idllib
IDOK
IDR
@@ -799,9 +775,8 @@ IIo
ILC
ILCo
ILD
ime
IMEs
IMPEXP
inbox
inclusivity
INCONTEXT
INDEXID
@@ -814,6 +789,7 @@ INITGUID
INITMENU
inkscape
INLINEPREFIX
inlines
inproc
Inputkeyinfo
Inputreadhandledata
@@ -826,7 +802,6 @@ INTERNALNAME
intsafe
INVALIDARG
INVALIDATERECT
Ioctl
ipch
ipsp
iterm
@@ -869,14 +844,12 @@ KLF
KLMNO
KOK
KPRIORITY
KVM
kyouhaishaheiku
langid
LANGUAGELIST
lasterror
LASTEXITCODE
LAYOUTRTL
lbl
LBN
LBUTTON
LBUTTONDBLCLK
@@ -897,10 +870,8 @@ LINESELECTION
LINEWRAP
LINKERRCAP
LINKERROR
linputfile
listptr
listptrsize
lld
llx
LMENU
lnkd
@@ -957,12 +928,11 @@ LPWINDOWPOS
lpwpos
lpwstr
LRESULT
lsb
LSBs
lsconfig
lstatus
lstrcmp
LTEXT
lto
ltsc
LUID
luma
@@ -984,6 +954,7 @@ MAKELRESULT
MAPBITMAP
MAPVIRTUALKEY
MAPVK
matrix'd
MAXDIMENSTRING
MAXSHORT
maxval
@@ -996,7 +967,6 @@ MBUTTONDOWN
MBUTTONUP
mdmerge
MDs
mdtauk
MEASUREITEM
megamix
memallocator
@@ -1050,9 +1020,9 @@ MSGMARKMODE
MSGSCROLLMODE
MSGSELECTMODE
msiexec
MSIL
msix
MSRC
msvcrt
MSVCRTD
MTSM
murmurhash
@@ -1063,6 +1033,7 @@ mydir
Mypair
Myval
NAMELENGTH
nameof
namestream
NCACTIVATE
NCCALCSIZE
@@ -1102,6 +1073,7 @@ NOCLIP
NOCOMM
NOCONTEXTHELP
NOCOPYBITS
nodiscard
NODUP
noexcepts
NOFONT
@@ -1116,7 +1088,6 @@ NOMOVE
NONALERT
nonbreaking
nonclient
NONINFRINGEMENT
NONPREROTATED
nonspace
NOOWNERZORDER
@@ -1134,6 +1105,7 @@ NOSIZE
NOSNAPSHOT
NOTHOUSANDS
NOTICKS
notif
NOTIMEOUTIFNOTHUNG
NOTIMPL
NOTOPMOST
@@ -1159,6 +1131,7 @@ ntuser
NTVDM
nugetversions
NUKTA
nullability
nullness
nullonfailure
nullopts
@@ -1198,8 +1171,6 @@ osc
OSDEPENDSROOT
OSG
OSGENG
oss
outdir
OUTOFCONTEXT
Outptr
outstr
@@ -1239,6 +1210,7 @@ PCONSOLEENDTASK
PCONSOLESETFOREGROUND
PCONSOLEWINDOWOWNER
pcoord
pcs
pcshell
PCSHORT
PCSR
@@ -1332,8 +1304,7 @@ PREVIEWLABEL
PREVIEWWINDOW
PREVLINE
prg
pri
prioritization
PRIs
processhost
PROCESSINFOCLASS
PRODEXT
@@ -1371,18 +1342,14 @@ PUCHAR
pvar
pwch
PWDDMCONSOLECONTEXT
Pwease
pweview
pws
pwstr
pwsz
pythonw
Qaabbcc
QUERYOPEN
quickedit
QUZ
QWER
Qxxxxxxxxxxxxxxx
qzmp
RAII
RALT
@@ -1405,18 +1372,17 @@ RCOCA
RCOCW
RCONTROL
RCOW
rcv
readback
READCONSOLE
READCONSOLEOUTPUT
READCONSOLEOUTPUTSTRING
READMODE
rectread
redef
redefinable
redist
REDSCROLL
REFCLSID
Reference'd
REFGUID
REFIID
REFPROPERTYKEY
@@ -1501,7 +1467,7 @@ SCRBUFSIZE
screenbuffer
SCREENBUFFERINFO
screeninfo
screenshots
screenshot
scriptload
scrollback
SCROLLFORWARD
@@ -1512,7 +1478,6 @@ SCROLLSCALE
SCROLLSCREENBUFFER
sddl
SDKDDK
segfault
SELCHANGE
SELECTEDFONT
SELECTSTRING
@@ -1599,7 +1564,7 @@ snapcy
snk
SOLIDBOX
Solutiondir
sourced
spec'd
SRCAND
SRCCODEPAGE
SRCCOPY
@@ -1630,6 +1595,7 @@ STDEXT
STDMETHODCALLTYPE
STDMETHODIMP
STGM
stl
STRINGTABLE
STRSAFE
STUBHEAD
@@ -1642,9 +1608,8 @@ SUBLANG
swapchain
swapchainpanel
SWMR
SWP
swrapped
SYMED
sync'd
SYNCPAINT
syscalls
SYSCHAR
@@ -1669,14 +1634,12 @@ TARGETNAME
targetver
tbc
tbi
Tbl
TBM
TCHAR
TCHFORMAT
TCI
tcommands
tdbuild
Tdd
TDP
Teb
Techo
@@ -1693,7 +1656,6 @@ testenvs
testlab
testlist
testmd
testname
TESTNULL
testpass
testpasses
@@ -1709,6 +1671,7 @@ TEXTMETRICW
textmode
texttests
TFCAT
threadpool
THUMBPOSITION
THUMBTRACK
tilunittests
@@ -1717,7 +1680,6 @@ titlebars
TITLEISLINKNAME
TLDP
TLEN
Tlgg
TMAE
TMPF
tmultiple
@@ -1731,7 +1693,6 @@ tracelogging
traceviewpp
trackbar
trackpad
transitioning
Trd
triaged
triaging
@@ -1748,6 +1709,7 @@ TTM
TTo
tvpp
tvtseq
typeparam
TYUI
uap
uapadmin
@@ -1772,6 +1734,7 @@ uldash
uldb
ULONGLONG
ulwave
Unaccess
Unadvise
unattend
UNCPRIORITY
@@ -1781,12 +1744,10 @@ unhosted
UNICODETEXT
UNICRT
Unintense
unittesting
Unittesting
unittests
unk
unknwn
UNORM
unparseable
untextured
UPDATEDISPLAY
UPDOWN
@@ -1831,12 +1792,9 @@ vga
vgaoem
viewkind
VIRAMA
Virt
VIRTTERM
visualstudiosdk
vkey
VKKEYSCAN
VMs
VPA
vpack
vpackdirectory
@@ -1886,21 +1844,15 @@ wddm
wddmcon
WDDMCONSOLECONTEXT
wdm
webpage
websites
wekyb
wewoad
wex
wextest
WFill
wfopen
WHelper
wic
WIDTHSCROLL
Widthx
Wiggum
wil
WImpl
WINAPI
winbasep
wincon
@@ -1940,11 +1892,9 @@ winmm
WINMSAPP
winnt
Winperf
WInplace
winres
winrt
winternl
winui
winuser
WINVER
wistd
@@ -1957,24 +1907,16 @@ WNDCLASSEX
WNDCLASSEXW
WNDCLASSW
Wndproc
WNegative
WNull
wordi
wordiswrapped
workarea
WOutside
WOWARM
WOWx
wparam
WPartial
wpf
wpfdotnet
WPR
WPrep
WPresent
wprp
wprpi
wrappe
wregex
writeback
WRITECONSOLE
@@ -1983,15 +1925,12 @@ WRITECONSOLEOUTPUT
WRITECONSOLEOUTPUTSTRING
wrkstr
wrl
WRL
wrp
WRunoff
WSLENV
wstr
wstrings
wsz
wtd
WTest
WTEXT
WTo
wtof
@@ -2000,8 +1939,6 @@ WTSOFTFONT
wtw
Wtypes
WUX
WVerify
WWith
wxh
wyhash
wymix
@@ -2015,34 +1952,22 @@ xbutton
XBUTTONDBLCLK
XBUTTONDOWN
XBUTTONUP
XCast
XCENTER
xcopy
XCount
xdy
XEncoding
xes
XFG
XFile
XFORM
XIn
xkcd
XManifest
XMath
XNamespace
xorg
XPan
XResource
xsi
xstyler
XSubstantial
XTest
XTPOPSGR
XTPUSHSGR
xtr
XTWINOPS
xunit
xutr
xvalue
XVIRTUALSCREEN
yact
YCast
@@ -2058,6 +1983,6 @@ Zabcdefghijklmn
Zabcdefghijklmnopqrstuvwxyz
ZCmd
ZCtrl
zero'd
ZWJs
ZYXWVU
ZYXWVUTd

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,51 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
# src/host/ut_host/AliasTests.cpp
\$\d\$[A-ZA-z]
# src/cascadia/TerminalSettingsEditor/Appearances.cpp
// Pwease call.*
# src/host/ft_host/CJK_DbcsTests.cpp
// \|Q.*|^\s+// \|\s*aa\w+
# App Package trailer
__[a-z\d]{13}\b
# src/host/ut_host/TextBufferTests.cpp
// \d\|.{10}\|
# contributors
\[@[-_\w]+\]
# src/types/CodepointWidthDetector.cpp
fallback to
Include=".*?"
^author = \w+
D2D
# Compiler flags
\s-D(?=[A-Z])
# Automatically suggested patterns
# hit-count: 26 file-count: 12
# unicode escaped characters (4)
\\u[0-9a-fA-F]{4}
# hit-count: 6 file-count: 5
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\\03[1-7]|\x1b|\\u\{1[Bb]\})\[(?:\d+(?:;\d+)*|)m(?=[a-z])
# profiles.schema.json
"pattern": ".*?"
# Intentionally reversed binomials
\b(?:bottom to top|down and up)\b
# Windows accelerators
\b[A-Z][a-z]*&[a-z]+(?!;)\b
@@ -43,7 +89,7 @@ L"[0-9A-F]{4}"
# hit-count: 3904 file-count: 577
# IServiceProvider / isAThing
(?:(?:\b|_|(?<=[a-z]))[IT]|(?:\b|_)(?:nsI|isA))(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
(?:(?:\b|_|(?<=[a-z]))[ITWX]|(?:\b|_)(?:nsI|isA))(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
# hit-count: 2437 file-count: 826
# #includes
@@ -130,7 +176,7 @@ mailto:[-a-zA-Z=;:/?%&0-9+@._]{3,}
# hit-count: 1 file-count: 1
# microsoft
\b(?:https?://|)(?:(?:(?:blogs|download\.visualstudio|docs|msdn2?|research)\.|)microsoft|blogs\.msdn)\.co(?:m|\.\w\w)/[-_a-zA-Z0-9()=./%]*
\b(?:https?://|)(?:(?:(?:blogs|download\.visualstudio|docs|msdn2?|research)\.|)microsoft|blogs\.msdn)\.co(?:m|\.\w\w)/[-_a-zA-Z0-9()=./%?#]*
# hit-count: 1 file-count: 1
# Punycode
@@ -171,7 +217,7 @@ Scro\&ll
:\\windows\\syste\b
TestUtils::VerifyExpectedString\(tb, L"[^"]+"
(?:hostSm|mach)\.ProcessString\(L"[^"]+"
\b([A-Za-z])\g{-1}{3,}\b
Base64::s_(?:En|De)code\(L"[^"]+"
VERIFY_ARE_EQUAL\(L"[^"]+"
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+/"
@@ -220,13 +266,15 @@ equals_insensitive_ascii\("\w+", "\w+"
# mount
\bmount\s+-t\s+(\w+)\s+\g{-1}\b
# C/idl types, repeated CSS values, + English ...
\s(auto|buffalo|center|div|Guid|GUID|inherit|long|LONG|none|normal|solid|that|thin|transparent|very)(?: \g{-1})+\s
\s(auto|await|buffalo|center|div|Guid|GUID|inherit|long|LONG|none|normal|solid|that|thin|transparent|very)(?:\s\g{-1})+\s
# C enum and struct
\b(?:enum|struct)\s+(\w+)\s+\g{-1}\b
# go templates
\s(\w+)\s+\g{-1}\s+\`(?:graphql|inject|json|yaml):
# doxygen / javadoc / .net
(?:[\\@](?:brief|defgroup|groupname|link|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+(?:static|override|readonly|required|virtual))*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s
# C# getter/setter
\s(\w+)\s+\g{-1}\s*\{\s*[gs]et;
# macOS file path
(?:Contents\W+|(?!iOS)/)MacOS\b

View File

@@ -1,25 +1,30 @@
^attache$
^attacher$
^attachers$
^bellow?$
attache
aroynt.*
bellows?
benefitting
occurences?
^dependan.*
^develope$
^developement$
^developpe
^Devers?$
^devex
^devide
^Devinn?[ae]
^devisal
^devisor
^diables?$
^oer$
.+dnt
dependan.*
developement
developp?e
Devers?
devex.*
devide
Devinn?[ae]
devisals?
devisors?
diables?
hasta?
hastat.*
immediatly
inisle
inital
linge
oer
Sorce
^[Ss]pae.*
^Teh$
^untill$
^untilling$
^venders?$
^wether.*
[Ss]pae.*
Teh
untill
untilling
venders?
wether.*

View File

@@ -55,7 +55,7 @@ name: Spell checking
# spelling:
# # remove `security-events: write` and `use_sarif: 1`
# # remove `experimental_apply_changes_via_bot: 1`
# ... otherwise adjust the `with:` as you wish
# ... otherwise, adjust the `with:` as you wish
on:
push:
@@ -74,6 +74,8 @@ on:
types:
- "created"
permissions: {}
jobs:
spelling:
name: Check Spelling
@@ -85,7 +87,7 @@ jobs:
outputs:
followup: ${{ steps.spelling.outputs.followup }}
runs-on: ubuntu-latest
if: ${{ contains(github.event_name, 'pull_request') || github.event_name == 'push' }}
if: ${{ (contains(github.event_name, 'pull_request') && github.event.pull_request.state == 'open') || github.event_name == 'push' }}
concurrency:
group: spelling-${{ github.event.pull_request.number || github.ref }}
# note: If you use only_check_changed_files, you do not want cancel-in-progress
@@ -93,7 +95,7 @@ jobs:
steps:
- name: check-spelling
id: spelling
uses: check-spelling/check-spelling@v0.0.25
uses: check-spelling/check-spelling@cfb6f7e75bbfc89c71eaa30366d0c166f1bd9c8c # v0.0.26
with:
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
checkout: true
@@ -105,47 +107,25 @@ jobs:
warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check,unclosed-block-ignore-begin,unclosed-block-ignore-end
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
use_sarif: 1
check_extra_dictionaries: ""
dictionary_source_prefixes: >
allow-hunspell: false
load-config-from: |
{
"cspell": "https://raw.githubusercontent.com/check-spelling/cspell-dicts/v20241114/dictionaries/"
"pr-base-keys": [
""
],
"pr-trusted-keys": [
"check_extra_dictionaries",
"dictionary_source_prefixes",
"extra_dictionaries",
""
],
"": []
}
extra_dictionaries: |
cspell:software-terms/softwareTerms.txt
cspell:cpp/stdlib-cpp.txt
cspell:cpp/stdlib-c.txt
cspell:python/python/python-lib.txt
cspell:php/php.txt
cspell:node/node.txt
cspell:dart/dart.txt
cspell:filetypes/filetypes.txt
cspell:java/java.txt
cspell:css/css.txt
cspell:dotnet/dotnet.txt
cspell:npm/npm.txt
cspell:fullstack/fullstack.txt
cspell:java/java-terms.txt
cspell:r/r.txt
cspell:golang/go.txt
cspell:cpp/stdlib-cmath.txt
cspell:typescript/typescript.txt
cspell:html/html.txt
cspell:cpp/compiler-msvc.txt
cspell:django/django.txt
cspell:aws/aws.txt
cspell:python/common/extra.txt
cspell:cpp/ecosystem.txt
cspell:cpp/lang-keywords.txt
cspell:csharp/csharp.txt
cspell:cpp/compiler-clang-attributes.txt
cspell:python/python/python.txt
cspell:mnemonics/mnemonics.txt
cspell:powershell/powershell.txt
comment-push:
name: Report (Push)
# If your workflow isn't running on push, you can remove this job
runs-on: ubuntu-latest
runs-on: ubuntu-slim
needs: spelling
permissions:
actions: read
@@ -153,27 +133,24 @@ jobs:
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.25
uses: check-spelling/check-spelling@cfb6f7e75bbfc89c71eaa30366d0c166f1bd9c8c # v0.0.26
with:
checkout: true
spell_check_this: microsoft/terminal@main
task: ${{ needs.spelling.outputs.followup }}
comment-pr:
name: Report (PR)
# If you workflow isn't running on pull_request*, you can remove this job
runs-on: ubuntu-latest
runs-on: ubuntu-slim
needs: spelling
permissions:
actions: read
contents: read
pull-requests: write
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.25
uses: check-spelling/check-spelling@cfb6f7e75bbfc89c71eaa30366d0c166f1bd9c8c # v0.0.26
with:
checkout: true
spell_check_this: microsoft/terminal@main
task: ${{ needs.spelling.outputs.followup }}
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
@@ -184,12 +161,13 @@ jobs:
contents: write
pull-requests: write
actions: read
runs-on: ubuntu-latest
runs-on: ubuntu-slim
if: ${{
github.repository_owner != 'microsoft' &&
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, '@check-spelling-bot apply') &&
contains(github.event.comment.body, '@check-spelling-bot') &&
contains(github.event.comment.body, 'apply') &&
contains(github.event.comment.body, 'https://')
}}
concurrency:
@@ -197,7 +175,7 @@ jobs:
cancel-in-progress: false
steps:
- name: apply spelling updates
uses: check-spelling/check-spelling@v0.0.25
uses: check-spelling/check-spelling@cfb6f7e75bbfc89c71eaa30366d0c166f1bd9c8c # v0.0.26
with:
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
checkout: true

View File

@@ -127,4 +127,5 @@
"**/obj/**": true,
"**/packages/**": true,
},
}
"sarif-viewer.connectToGithubCodeScanning": "on",
}

View File

@@ -15,7 +15,6 @@
- [Via Chocolatey (unofficial)](#via-chocolatey-unofficial)
- [Via Scoop (unofficial)](#via-scoop-unofficial)
- [Installing Windows Terminal Canary](#installing-windows-terminal-canary)
- [Windows Terminal Roadmap](#windows-terminal-roadmap)
- [Terminal \& Console Overview](#terminal--console-overview)
- [Windows Terminal](#windows-terminal)
- [The Windows Console Host](#the-windows-console-host)
@@ -178,11 +177,6 @@ _Learn more about the [types of Windows Terminal distributions](https://learn.mi
---
## Windows Terminal Roadmap
The plan for the Windows Terminal [is described here](/doc/roadmap-2023.md) and
will be updated as the project proceeds.
## Terminal & Console Overview
Please take a few minutes to review the overview below before diving into the

View File

@@ -1,4 +1,5 @@
{
"codebaseName": "VSTS_Microsoft_OSGS_OpenConsole",
"instanceUrl": "https://microsoft.visualstudio.com",
"projectName": "OS",
"areaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SHINE\\Terminal",

View File

@@ -0,0 +1,64 @@
trigger: none
pr: none
schedules:
- cron: "30 3 * * 2-6" # Run at 03:30 UTC Tuesday through Saturday (After the work day in Pacific, Mon-Fri)
displayName: "Nightly Terminal Build"
branches:
include:
- main
always: false # only run if there's code changes!
parameters:
- name: publishToAzure
displayName: "Deploy to **PUBLIC** Azure Storage"
type: boolean
default: true
- name: official
displayName: "Run on Official 1ES Pipeline Templates"
type: boolean
default: true
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
variables:
- template: templates-v2/variables-nuget-package-version.yml
parameters:
branding: Canary
extends:
template: templates-v2/pipeline-1espt-full-release-build.yml
parameters:
official: ${{ parameters.official }}
branding: Canary
buildTerminal: true
pgoBuildMode: Optimize
codeSign: true
signingIdentity:
serviceName: $(SigningServiceName)
appId: $(SigningAppId)
tenantId: $(SigningTenantId)
akvName: $(SigningAKVName)
authCertName: $(SigningAuthCertName)
signCertName: $(SigningSignCertName)
useManagedIdentity: $(SigningUseManagedIdentity)
clientId: $(SigningOriginalClientId)
publishSymbolsToPublic: true
symbolExpiryTime: 15
symbolPublishingSubscription: $(SymbolPublishingServiceConnection)
symbolPublishingProject: $(SymbolPublishingProject)
${{ if eq(true, parameters.publishToAzure) }}:
extraPublishJobs:
- template: build/pipelines/templates-v2/job-deploy-to-azure-storage.yml@self
parameters:
pool:
name: SHINE-INT-S
os: windows
dependsOn: [PublishSymbols]
storagePublicRootURL: $(AppInstallerRootURL)
subscription: $(AzureSubscriptionName)
storageAccount: $(AzureStorageAccount)
storageContainer: $(AzureStorageContainer)
buildConfiguration: Release
buildPlatforms: [x64, x86, arm64]
environment: production-canary

View File

@@ -30,9 +30,13 @@ parameters:
- name: signingIdentity
type: object
default: {}
- name: outerTemplateContext
type: object
default: {}
jobs:
- job: ${{ parameters.jobName }}
templateContext: ${{ parameters.outerTemplateContext }}
${{ if ne(length(parameters.pool), 0) }}:
pool: ${{ parameters.pool }}
${{ if eq(parameters.codeSign, true) }}:

View File

@@ -74,9 +74,13 @@ parameters:
- name: afterBuildSteps
type: stepList
default: []
- name: outerTemplateContext
type: object
default: {}
jobs:
- job: ${{ parameters.jobName }}
templateContext: ${{ parameters.outerTemplateContext }}
${{ if ne(length(parameters.pool), 0) }}:
pool: ${{ parameters.pool }}
strategy:

View File

@@ -35,9 +35,13 @@ parameters:
- name: signingIdentity
type: object
default: {}
- name: outerTemplateContext
type: object
default: {}
jobs:
- job: ${{ parameters.jobName }}
templateContext: ${{ parameters.outerTemplateContext }}
${{ if ne(length(parameters.pool), 0) }}:
pool: ${{ parameters.pool }}
${{ if eq(parameters.codeSign, true) }}:

View File

@@ -30,9 +30,13 @@ parameters:
- name: signingIdentity
type: object
default: {}
- name: outerTemplateContext
type: object
default: {}
jobs:
- job: ${{ parameters.jobName }}
templateContext: ${{ parameters.outerTemplateContext }}
${{ if ne(length(parameters.pool), 0) }}:
pool: ${{ parameters.pool }}
${{ if eq(parameters.codeSign, true) }}:

View File

@@ -0,0 +1,233 @@
parameters:
- name: official
type: boolean
default: false
- name: branding
type: string
default: Release
values:
- Release
- Preview
- Canary
- Dev
- name: buildTerminal
type: boolean
default: true
- name: buildConPTY
type: boolean
default: false
- name: buildWPF
type: boolean
default: false
- name: pgoBuildMode
type: string
default: Optimize
values:
- Optimize
- Instrument
- None
- name: buildConfigurations
type: object
default:
- Release
- name: buildPlatforms
type: object
default:
- x64
- x86
- arm64
- name: codeSign
type: boolean
default: true
- name: terminalInternalPackageVersion
type: string
default: '0.0.8'
- name: publishSymbolsToPublic
type: boolean
default: true
- name: symbolExpiryTime
type: string
default: 36530 # This is the default from PublishSymbols@2
- name: symbolPublishingSubscription
type: string
- name: symbolPublishingProject
type: string
- name: extraPublishJobs
type: object
default: []
- name: signingIdentity
type: object
default: {}
resources:
repositories:
- repository: 1esPipelines
type: git
name: 1ESPipelineTemplates/1ESPipelineTemplates
ref: refs/tags/release
extends:
${{ if eq(parameters.official, true) }}:
template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines
${{ else }}:
template: v1/1ES.Unofficial.PipelineTemplate.yml@1esPipelines
parameters:
customBuildTags:
- 1ES.PT.ViaStartRight
pool:
name: SHINE-INT-L
os: windows
sdl:
tsa:
enabled: true
configFile: '$(Build.SourcesDirectory)\build\config\tsa.json'
binskim:
enabled: true
policheck:
enabled: false
severity: Note
baseline:
baselineFile: '$(Build.SourcesDirectory)\build\config\release.gdnbaselines'
suppressionSet: default
stages:
- stage: Build
displayName: Build
dependsOn: []
jobs:
- template: ./build/pipelines/templates-v2/job-build-project.yml@self
parameters:
outerTemplateContext:
outputs:
- output: pipelineArtifact
targetPath: $(JobOutputDirectory)
artifactName: $(JobOutputArtifactName)
publishArtifacts: false # Handled by 1ESPT
branding: ${{ parameters.branding }}
buildTerminal: ${{ parameters.buildTerminal }}
buildConPTY: ${{ parameters.buildConPTY }}
buildWPF: ${{ parameters.buildWPF }}
pgoBuildMode: ${{ parameters.pgoBuildMode }}
buildConfigurations: ${{ parameters.buildConfigurations }}
buildPlatforms: ${{ parameters.buildPlatforms }}
generateSbom: false # this is handled by 1ESPT
removeAllNonSignedFiles: true # appease the overlords
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
beforeBuildSteps:
- template: ./build/pipelines/templates-v2/steps-setup-versioning.yml@self
- template: ./build/pipelines/templates-v2/steps-install-terrapin.yml@self
- task: UniversalPackages@0
displayName: Download terminal-internal Universal Package
inputs:
feedListDownload: 2b3f8893-a6e8-411f-b197-a9e05576da48
packageListDownload: e82d490c-af86-4733-9dc4-07b772033204
versionListDownload: ${{ parameters.terminalInternalPackageVersion }}
- ${{ if eq(parameters.buildWPF, true) }}:
# Add an Any CPU build flavor for the WPF control bits
- template: ./build/pipelines/templates-v2/job-build-project.yml@self
parameters:
outerTemplateContext:
outputs:
- output: pipelineArtifact
targetPath: $(JobOutputDirectory)
artifactName: $(JobOutputArtifactName)
publishArtifacts: false # Handled by 1ESPT
jobName: BuildWPF
branding: ${{ parameters.branding }}
buildTerminal: false
buildWPFDotNetComponents: true
buildConfigurations: ${{ parameters.buildConfigurations }}
buildPlatforms:
- Any CPU
generateSbom: false # this is handled by 1ESPT
removeAllNonSignedFiles: true # appease the overlords
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
beforeBuildSteps:
- template: ./build/pipelines/templates-v2/steps-setup-versioning.yml@self
# WPF doesn't need the localizations or the universal package, but if it does... put them here.
- stage: Package
displayName: Package
dependsOn: [Build]
jobs:
- ${{ if eq(parameters.buildTerminal, true) }}:
- template: ./build/pipelines/templates-v2/job-merge-msix-into-bundle.yml@self
parameters:
pool:
name: SHINE-INT-S
os: windows
outerTemplateContext:
outputs:
- output: pipelineArtifact
targetPath: $(JobOutputDirectory)
artifactName: $(JobOutputArtifactName)
publishArtifacts: false # Handled by 1ESPT
jobName: Bundle
branding: ${{ parameters.branding }}
buildConfigurations: ${{ parameters.buildConfigurations }}
buildPlatforms: ${{ parameters.buildPlatforms }}
generateSbom: false # Handled by 1ESPT
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
- ${{ if eq(parameters.buildConPTY, true) }}:
- template: ./build/pipelines/templates-v2/job-package-conpty.yml@self
parameters:
pool:
name: SHINE-INT-S
os: windows
outerTemplateContext:
outputs:
- output: pipelineArtifact
targetPath: $(JobOutputDirectory)
artifactName: $(JobOutputArtifactName)
publishArtifacts: false # Handled by 1ESPT
buildConfigurations: ${{ parameters.buildConfigurations }}
buildPlatforms: ${{ parameters.buildPlatforms }}
generateSbom: false # this is handled by 1ESPT
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
- ${{ if eq(parameters.buildWPF, true) }}:
- template: ./build/pipelines/templates-v2/job-build-package-wpf.yml@self
parameters:
pool:
name: SHINE-INT-S
os: windows
outerTemplateContext:
outputs:
- output: pipelineArtifact
targetPath: $(JobOutputDirectory)
artifactName: $(JobOutputArtifactName)
publishArtifacts: false # Handled by 1ESPT
buildConfigurations: ${{ parameters.buildConfigurations }}
buildPlatforms: ${{ parameters.buildPlatforms }}
generateSbom: false # this is handled by 1ESPT
codeSign: ${{ parameters.codeSign }}
signingIdentity: ${{ parameters.signingIdentity }}
- stage: Publish
displayName: Publish
dependsOn:
- Build
- ${{ if or(parameters.buildTerminal, parameters.buildConPTY, parameters.buildWPF) }}:
- Package
jobs:
- template: ./build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml@self
parameters:
pool:
name: SHINE-INT-S
os: windows
includePublicSymbolServer: ${{ parameters.publishSymbolsToPublic }}
symbolExpiryTime: ${{ parameters.symbolExpiryTime }}
subscription: ${{ parameters.symbolPublishingSubscription }}
symbolProject: ${{ parameters.symbolPublishingProject }}
- ${{ parameters.extraPublishJobs }}

View File

@@ -153,7 +153,10 @@ stages:
- stage: Publish
displayName: Publish
pool: ${{ parameters.pool }}
dependsOn: [Build, Package]
dependsOn:
- Build
- ${{ if or(parameters.buildTerminal, parameters.buildConPTY, parameters.buildWPF) }}:
- Package
jobs:
# We only support the vpack for Release builds that include Terminal
- ${{ if and(containsValue(parameters.buildConfigurations, 'Release'), parameters.buildTerminal, parameters.publishVpackToWindows) }}:

View File

@@ -211,7 +211,7 @@ extends:
ob_createvpack_verbose: true
ob_createvpack_vpackdirectory: '$(JobOutputDirectory)\vpack'
ob_createvpack_versionAs: string
ob_createvpack_version: '$(XES_APPXMANIFESTVERSION)'
ob_createvpack_version: '$(XES_PACKAGEVERSIONNUMBER)'
ob_updateOSManifest_gitcheckinConfigPath: '$(Build.SourcesDirectory)\build\config\GitCheckin.json'
# We're skipping the 'fetch' part of the OneBranch rules, but that doesn't mean
# that it doesn't expect to have downloaded a manifest directly to some 'destination'
@@ -279,7 +279,10 @@ extends:
- stage: Publish
displayName: Publish
dependsOn: [Build]
dependsOn:
- Build
- ${{ if or(parameters.buildTerminal, parameters.buildConPTY, parameters.buildWPF) }}:
- Package
jobs:
- template: ./build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml@self
parameters:

View File

@@ -0,0 +1,6 @@
steps:
- pwsh: |-
nuget install -source "https://pkgs.dev.azure.com/microsoft/_packaging/WindowsTerminal/nuget/v3/index.json" TerrapinRetrievalTool -Prerelease -OutputDirectory _trt
$TerrapinRetrievalToolPath = (Get-Item _trt\TerrapinRetrievalTool.*\win-x64\TerrapinRetrievalTool.exe).FullName
Write-Host "##vso[task.setvariable variable=X_VCPKG_ASSET_SOURCES]x-script,${TerrapinRetrievalToolPath} -b https://vcpkg.storage.devpackages.microsoft.io/artifacts/ -a true -u None -p {url} -s {sha512} -d {dst};x-block-origin"
displayName: Set up the Terrapin Retrieval Tool (vcpkg cache)

View File

@@ -63,7 +63,7 @@ When console applications are launched, the Windows Console Host determines whic
2. Overlay settings specified by the user's configured defaults
3. Overlay application-specific settings from either the registry or the shortcut file, depending on how the application was launched
Note that the registry settings are "sparse" settings repositories, meaning that if a setting isn't present, then whatever value that is already in use remains unchanged. This allows users to have some settings shared amongst all console applications and other settings be specific. Shortcut files, however, store each setting regardless of whether it was a default setting or not.
Note that the registry settings are "sparse" settings repositories, meaning that if a setting isn't present, then whatever value that is already in use remains unchanged. This allows users to have some settings shared amongst all console applications and other settings be specific. Shortcut files, however, store each setting regardless of whether or not it was a default setting.
## Known Issues

View File

@@ -60,7 +60,8 @@
"enum": [
"audible",
"window",
"taskbar"
"taskbar",
"notification"
]
}
},
@@ -70,6 +71,7 @@
"audible",
"taskbar",
"window",
"notification",
"all",
"none"
]
@@ -1765,7 +1767,7 @@
]
},
"ExportBufferAction": {
"description": "Arguments corresponding to a exportBuffer Action",
"description": "Arguments corresponding to an exportBuffer Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
@@ -2242,7 +2244,7 @@
"$ref": "#/$defs/Icon"
},
"name": {
"description": "The name that will appear in the command palette. If one isn't provided, the terminal will attempt to automatically generate a name.\nIf name is a string, it will be the name of the command.\nIf name is a object, the key property of the object will be used to lookup a localized string resource for the command",
"description": "The name that will appear in the command palette. If one isn't provided, the terminal will attempt to automatically generate a name.\nIf name is a string, it will be the name of the command.\nIf name is an object, the key property of the object will be used to lookup a localized string resource for the command",
"type": [
"string",
"object",
@@ -2654,10 +2656,21 @@
"type": "string"
},
"warning.confirmCloseAllTabs": {
"deprecated": true,
"description": "[Deprecated] Use \"warning.confirmOnClose\" instead.",
"default": true,
"description": "When set to \"true\" closing a window with multiple tabs open will require confirmation. When set to \"false\", the confirmation dialog will not appear.",
"type": "boolean"
},
"warning.confirmOnClose": {
"default": "automatic",
"description": "Controls when a confirmation dialog appears before closing tabs or windows.",
"enum": [
"never",
"automatic",
"always"
],
"type": "string"
},
"useTabSwitcher": {
"description": "[Deprecated] Replaced with the \"tabSwitcherMode\" setting.",
"default": true,
@@ -3174,6 +3187,11 @@
"mingw"
],
"type": "string"
},
"dragDropDelimiter": {
"default": " ",
"description": "The delimiter used when dropping multiple files onto the terminal.",
"type": "string"
}
}
},

View File

@@ -55,7 +55,7 @@ Edge cases:
1. Multiple monitors. The user should be able to set the initial position to any monitors attached. For the monitors on the left side of the major monitor, the initial position values are negative.
2. If the initial position is larger than the screen resolution and the window top left corner is off-screen, we should let user be able to see and drag the window back on screen. One solution is to set the initial position to the top left corner of the nearest monitor if the top left is off-screen.
3. If the user wants to launch maximized and provides an initial position, we should launch the maximized window on the top left corner of the monitor where the position is located.
3. If the user wants to launch maximized and provides an initial position, we should launch the maximized window at the top left corner of the monitor where the position is located.
4. Launch the Terminal on a monitor with custom dpi. Changing the dpi of the monitor will not affect the initial position of the top left corner. So we do not need to handle this case.
5. Launch the Terminal on a monitor with custom resolution. Changing the resolution will change the available point for the initial position. (2) already covers this case.
@@ -73,7 +73,7 @@ The rest of the UI will be the same of the current Terminal experience, except t
Users can only set the initial position and launch mode in the Json file with keyboard. Thus, this will not affect accessibility.
### Reliability
We need to make sure that whatever the initial position is set, the user can access the Terminal window. This is guaranteed because if the top left corner position of the Terminal Window is out of screen, we put it on the top left corner of the screen.
We need to make sure that whatever the initial position is set, the user can access the Terminal window. This is guaranteed because if the top left corner position of the Terminal Window is out of screen, we put it at the top left corner of the screen.
### Performance, Power, and Efficiency

View File

@@ -68,7 +68,7 @@ allows the terminal to expose quick actions for:
### User Stories
This is a bit of a unusual section, as this feature was already partially
This is a bit of an unusual section, as this feature was already partially
implemented when this spec was written.
Story | Size | Description

View File

@@ -189,7 +189,7 @@ However, for actions that _do_ require args, we'll set up a global function that
can be used to parse a json blob into an `IActionArgs`.
Once the `IActionArgs` is built for the keybinding, we'll set it in
`AppKeyBindings` with a updated `AppKeyBindings::SetKeyBinding` call.
`AppKeyBindings` with an updated `AppKeyBindings::SetKeyBinding` call.
`SetKeyBinding`'s signature will be updated to take a `ActionAndArgs` instead.
Should an action not need arguments, the `Args` member can be left `null` in the
`ActionAndArgs`.

View File

@@ -100,7 +100,7 @@ No expected change
<tr>
<td><strong>Compatibility</strong></td>
<td>
This entire spec outlines how this feature is designed with a emphasis on future
This entire spec outlines how this feature is designed with an emphasis on future
compatibility. As such, there are no expected regressions in the future when we
do add support for themes.
</td>

View File

@@ -141,7 +141,7 @@ Pressing the `openTabSwitcher` keychord again will not close the switcher, it'll
We'll provide a setting that will allow the list of tabs to be presented in either _in-order_ (how the tabs are ordered on the tab bar), or _Most Recently Used Order_ (MRU). MRU means that the tab that the terminal most recently visited will be on the top of the list, and the tab that the terminal has not visited for the longest time will be on the bottom.
There will be an argument for the `openTabSwitcher` action called `displayOrder`. This can be either `inOrder` or `mruOrder`. Making the setting an argument passed into `openTabSwitcher` would allow the user to have one keybinding to open an MRU Tab Switcher, and different one for the In-Order Tab Switcher. For example:
There will be an argument for the `openTabSwitcher` action called `displayOrder`. This can be either `inOrder` or `mruOrder`. Using an argument passed into `openTabSwitcher` would allow the user to have one keybinding to open an MRU Tab Switcher, and different one for the In-Order Tab Switcher. For example:
```
{"keys": ["ctrl+tab"], "command": {"action": "openTabSwitcher", "anchor":"ctrl", "displayOrder":"mruOrder"}}
{"keys": ["ctrl+shift+p"], "command": {"action": "openTabSwitcher", "anchor":"ctrl", "displayOrder":"inOrder"}}

View File

@@ -103,7 +103,7 @@ This option was not chosen because it added too much overhead for changing a set
### 2: Lock Button
Every setting will have a lock button next to it. If the lock is locked, that means the setting is being inherited from Global, and the control is disabled. If the user wants to edit the setting, they can click the lock, which will changed it to the unlocked lock icon, and the control will become enabled.
Every setting will have a lock button next to it. If the lock is locked, that means the setting is being inherited from Global, and the control is disabled. If the user wants to edit the setting, they can click the lock, which will change it to the unlocked lock icon, and the control will become enabled.
![Locks inheritance](./inheritance-locks.png)

View File

@@ -9,7 +9,7 @@ issue id: #1564
## Abstract
This spec describes the basic functionality of the settings UI, including disabling it, the navigation items, launch methods, and editing of settings. The specific layout of each page will defined in later design reviews.
This spec describes the basic functionality of the settings UI, including disabling it, the navigation items, launch methods, and editing of settings. The specific layout of each page will be defined in later design reviews.
## Inspiration

View File

@@ -71,7 +71,7 @@ There are five `type`s of objects in this menu:
the user to visually space out entries.
* `"type":"folder"`: This represents a nested menu of entries.
- The `"name"` property provides a string of text to display for the group.
- The `"icon"` property provides a path to a image to use as the icon. This
- The `"icon"` property provides a path to an image to use as the icon. This
property is optional.
- The `"entries"` property specifies a list of menu entries that will appear
nested under this entry. This can contain other `"type":"folder"` groups as

View File

@@ -377,7 +377,7 @@ spec's review.
* [ ] Enable previewing `sendInput` actions in the Command Palette and `SuggestionsControl`
* [ ] Enable the `SuggestionsControl` to open top-down (aligned to the bottom of the cursor row) or bottom-up (aligned to the top of the cursor row).
* [ ] Disable sorting on the `SuggestionsControl` - elements should presumably be pre-sorted by the source.
* [ ] Expose the recent commands as a accessor on `TermControl`
* [ ] Expose the recent commands as an accessor on `TermControl`
* [ ] Add a `suggestions` action which accepts a single option `recentCommands`. These should be fed in MRU order to the `SuggestionsControl`.
* [ ] Expose the recent directories as an accessor on `TermControl`, and add a `recentDirectories` source.
@@ -505,7 +505,7 @@ Here's a sample json schema for the settings discussed here.
> committing any plans here._
It would be beneficial for the Suggestions UI to display additional context to
the user. Consider a extension that provides some commands for the user, like a
the user. Consider an extension that provides some commands for the user, like a
hypothetical "Docker" extension. The extension author might be able to give the
commands simplified names, but also want to expose a more detailed description
of the commands to the user.

View File

@@ -36,7 +36,7 @@ We will do this by allowing users to define a dictionary in their settings.json
### Axes of variation
Specifying axes of variation is done in an extremely similar manner to the way font features are specified - a 4-character tag is used to specify which font axis is being modified and a numerical value is provided to specify the value the axis should be set to. For example, {'slnt', 20} specifies that the 'slant' axis should be set to 20.
Specifying axes of variation is done in an extremely similar manner to the way font features are specified - a 4-character tag is used to specify which font axis is being modified and a numerical value is provided to specify the value for the axis. For example, {'slnt', 20} specifies that the 'slant' axis should be set to 20.
There is also a standard list of axes of variation, and each axis has its own default. We will approach this the same way we approached font features, by allowing users to specify additional features or omit features without needing to redefine the defaults.

View File

@@ -229,7 +229,7 @@ with the default profile running `wsl` in it.
We'll add another action that can be used to toggle the visibility of the
command palette. Pressing that keybinding will bring up the command palette. We
should make sure to add a argument to this action that specifies whether the
should make sure to add an argument to this action that specifies whether the
palette should be opened directly in Action Mode or Commandline Mode.
When the command palette appears, we'll want it to appear as a single overlay
@@ -525,7 +525,7 @@ default. These are largely the actions that are bound by default.
## Addenda
This spec also has a follow-up spec which introduces further changes upon this
original draft. Please also refer to:
original draft. Please refer to:
* June 2020: Unified keybindings and commands, and synthesized action names.
@@ -578,7 +578,7 @@ original draft. Please also refer to:
in commandline mode before we try to auto-parse their commandline, to check
for errors. Might be useful to help sanity check users. We can always parse
their `wt` commandlines safely without having to execute them.
* It would be cool if the commands the user typed in Commandline Mode could be
* It would be cool if commands the user typed in Commandline Mode could be
saved to a history of some sort, so they could easily be re-entered.
- It would be especially cool if it could do this across launches.
- We don't really have any way of storing transient data like that in the

View File

@@ -68,7 +68,7 @@ This workflow affords us several benefits:
- This also makes it potentially possible to backport this portion of the code change to popular in-market versions of Windows 10. For instance, WSL2 has just backported to 1903 and 1909. The less churn and risk, the easier it is to sell a backport.
*Potential future:*
- ~~If no updated console exists, potentially check for registration of a terminal UX that is willing to use the inbox ConPTY bits, start it, and transition to being a PTY instead.~~
- ~~If no updated console exists, potentially check for registration of a terminal UX that is willing to use the inbox ConPTY bits, start it, and transition to being a PTY instead.~~
- **CUT FROM v1**: To simplify the story for end-users, we're offering this as a package deal in the first revision. Explaining the difference between consoles and terminals to end users is very difficult.
The registration would operate as follows:
@@ -80,7 +80,7 @@ The registration would operate as follows:
- **V1 NOTE:** The subkey `%%Startup` was chosen to separate these keys (this one and the `DelegationTerminal` one below) in case we needed to ACL them or protect them in some way. We want a per-user choice of which Terminal/Console are used, but we might need to take action to prevent these keys from being slammed at some point in the future. Why `%%`? The subkeys are traditionally used to resolve paths to client binaries that have their own console preferences set. The `%%` should never be resolvable as it won't lead to a valid path or expanded path variable.
The delegation process would operate as follows:
- A method contract is established between the existing inbox console and any updated console (an interface).
- A method contract is established between the existing inbox console and any updated console (an interface).
- `HRESULT ConsoleEstablishHandoff(HANDLE server, HANDLE driverInputEvent, const PortableConnectMessage* const msg, HANDLE signalPipe, HANDLE inboxProcess, HANDLE* process)`
- `HANDLE server`: This is the server side handle to the console driver, used with `DeviceIoControl` to receive/send messages with the client command-line application
- `HANDLE driverInputEvent`: The input event is created and assigned to the driver immediately on first connection, before any messages are read from the driver, to ensure that it can track a blocking state should first message be an input request that we do not yet have data to fill. As such, the inbox console will have created this and assigned it to the driver before pulling off the connection packet and determining that it wants to delegate. Therefore, we will transfer ownership of this event to the updated console.
@@ -88,7 +88,7 @@ The delegation process would operate as follows:
- ~~The `ConsoleArguments` structure could technically change between versions, so we will make a version agnostic portable structure that just carries the communication from the old one to the new one.~~
- **CUT FROM V1**: The only arguments coming in from a default light-up are the server handle. Pretty much all the other arguments are related to the operation of the PTY. Since this feature is about "default application" launches where no arguments are specified, this was cut from the initial revision.
- `const PortableConnectMessage* const msg`:
- The `CONSOLE_API_MSG` structure contains both the actual packet data from the driver as well as some overhead/administration data related to the packet state, ordering, completion, errors, and buffers. It's a broad scope structure for every type of message we process and it can change over time as we improve the way the `conserver.lib` handles packets.
- The `CONSOLE_API_MSG` structure contains both the actual packet data from the driver as well as some overhead/administration data related to the packet state, ordering, completion, errors, and buffers. It's a broad scope structure for every type of message we process and it can change over time as we improve the way that `conserver.lib` handles packets.
- This represents a version agnostic variant for ONLY the connect message that can pass along the initial connect information structure, the packet sequencing information, and other relevant payload only to that one message type. It will purposefully discard references to things like a specific set of API servicing routines because the point of handing off is to get updated routines, if necessary.
- **V1 NOTE:** This was named `CONSOLE_PORTABLE_ATTACH_MSG`
- `HANDLE signalPipe`: During authoring, it was identified that <kbd>Ctrl+C</kbd> and other similar signals need to make it back to the original `conhost.exe` application as the Operating System grants it special privilege over the originally attached client application. This privilege cannot be transferred to the delegated console. So this channel remains for the delegated one to send its signals back through the original one for commanding the underlying client. (This also implies the original `conhost.exe` inbox cannot close and must remain a part of the process tree for the life of the session to maintain this control.)
@@ -100,7 +100,7 @@ The delegation process would operate as follows:
1. ~~The issue of passing the server, event, and other handles into another process space. We're not entirely sure if the console driver will happily accept these things moving to a different process. It probably should, but unconfirmed.~~
1. ~~Some command-line client applications rely on spelunking the process tree to figure out who is their servicing application. Maintaining the delegated/updated console inside the same process space maintains some level of continuity for these sorts of applications.~~
- **Alternative:** We may make this just be a COM server/client contract. ~~An in-proc COM server should operate in much the same fashion here (loading the DLL into the process and running particular method) while being significantly more formal and customizable (version revisions, moving to out-of-proc, not really needing to know the binary path because the catalog knows).~~
- **V1 NOTE:** We landed on an out-of-proc COM server/client here. This maintains the isolation of the newly running code from the old code. Since we're maintaining the original `conhost.exe` for signaling purposes, we're no longer worried about the spelunking the process tree and not having the relationship for clients to find.
- **V1 NOTE:** We landed on an out-of-proc COM server/client here. This maintains the isolation of the newly running code from the old code. Since we're maintaining the original `conhost.exe` for signaling purposes, we're no longer worried about spelunking the process tree and not having the relationship for clients to find.
- **Not considering:** ~~WinRT. `conhost.exe` has no WinRT. Adding WinRT to it would significantly increase the complexity of compilation in the inbox and out of box code base. It would also significantly increase the compilation time, binary size, library link list, etc... unless we use just the ABI to access it. But I don't see an advantage to that over just using classic COM at that point. This is only one handoff method and a rather simplistic one at that. Every benefit WinRT provides is outweighed by the extra effort that would be required over just a classic COM server in this case.~~
- After delegation is complete, the inbox console will have to clean up any threads, handles, and state related to the session. We do a fairly good job with this normally, but some portions of the `conhost.exe` codebase are reliant on the process exiting for final cleanup. There may be a bit of extra effort to do some explicit cleanup here.
- **V1 NOTE:** The inbox one cleans up everything it can and sits in a state waiting for the child/delegated process handle to exit. It also maintains a thread listening for the signals to come through in case it needs to send a command to the client application using the privilege granted to it by the driver.
@@ -177,7 +177,7 @@ The settings experience includes:
- Inside Windows Terminal
- Inside the new Settings UI, we will likely need a page that configures the delegation keys in `HKCU\Console\%%Startup` ~~or a link out to the Windows Settings panel, should we manage to get the settings configurable there~~.
- Inside the console property sheet
- Same as for Terminal but with `comctl` controls over XAML +/- a link to the Windows Settings panel
- Same as Terminal, but with `comctl` controls over XAML +/- a link to the Windows Settings panel
- Inside the Settings panel for Windows (probably on the developer settings page)
- The ultimate location for this is likely a panel directly inside Windows. This is the hardest one to accomplish because of the timelines of the Windows product. We may not get this in an initial revision, but it should likely be our ultimate goal. **V1 NOTE:** We did it!
- Operation:
@@ -185,7 +185,7 @@ The settings experience includes:
- Offer a list of registered servers or discovered manifests from the app catalog - This is the ideal scenario where we search the installed app catalog +/- the COM catalog and offer a list of apps that conform to the contract in a drop-down.
- The final process was to use [App Extensions](https://docs.microsoft.com/windows/uwp/launch-resume/how-to-create-an-extension) inside the Terminal APPX package to declare the COM GUIDs that were available for the `DelegationConsole` and `DelegationTerminal` fields respectively. A configuration class `DelegationConfig` was added to `propslib.lib` that enables the lookup of these from the application state catalog and presents a list of them to choose from. It also manages reading and writing the registry keys.
- **V1 NOTE:** Our configuration options currently allow pairings of replacement consoles and terminals to be adjusted in lock-step from the UI. That's not to say further combinations are not possible or even necessarily inhibited by the code. We just went for minimal confusion in our first round.
- Configuration of the legacy console state:
- ~~Since we could end up in an experience where the default launch experience gets you directly into Windows Terminal, we believe that the Terminal will likely need an additional setting or settings in the new Settings UI that will allow the toggling of some of the `HKCU\Console` values to do things like set/remove the legacy console state.~~ **V1 NOTE:** Cut as low priority. Switch back to console and configure it that way or use the existing property sheet or tamper with registry keys.
- We have left the per-launch debugging and advanced access hole of calling something like `conhost.exe cmd.exe` which will use the inbox conhost to launch `cmd.exe` even if there is a default specified.
@@ -209,9 +209,9 @@ The major players here that I am considering are NVDA, JAWS, and Narrator. As fa
Let's hit the elephant in the room. "You plan on pulling a completely different binary inside the `conhost.exe` process and just... delegating all activity to it?" Yes.
(**V1 NOTE:** Well, it's out of proc now. But it is at the same privilege level as the original one thanks to the mechanics of COM.)
(**V1 NOTE:** Well, it's out of proc now. But it is at the same privilege level as the original one thanks to the mechanics of COM.)
As far as I'm concerned, the `conhost.exe` that is started to host the command-line client application is running at the same integrity level as the client binary that is partially started and waiting for its server to be ready. This is the long-standing existing protection that we have from the Windows operating system. Anything running in the same integrity level is already expected to be able to tamper with anything else at the same integrity level. The delegated binary that we would be loading into our process space will also be at the same integrity level. Nothing really stops a malicious actor from launching that binary in any other way in the same integrity level as a part of the command-line client application's startup.
As far as I'm concerned, the `conhost.exe` that is started to host the command-line client application is running at the same integrity level as the client binary that is partially started and waiting for its server to be ready. This is the long-standing existing protection that we have from the Windows operating system. Anything running in the same integrity level is already expected to be able to tamper with anything else at the same integrity level. The delegated binary that we would be loading into our process space will also be at the same integrity level. Nothing really stops a malicious actor from launching that binary in any other way in the same integrity level as a part of the command-line client application's startup.
The mitigation here, if necessary, would be to use `WinVerifyTrust` to validate the certification path of the `OpenConsole.exe` binary to ensure that only one that is signed by Microsoft can be the substitute server host for the application. This doesn't stop third parties from redistributing our `OpenConsole.exe` off of GitHub if necessary with their products, but it would stop someone from introducing any random binary that met the signature interface of the delegation methods into `conhost.exe`. The only value I see this providing is stopping someone from being "tricked" into delegating their `conhost.exe` to another binary through the configuration methods we provide. It doesn't really stop someone (or an attacker) from taking ownership of the `conhost.exe` in System32 and replacing it directly. So this point might be moot. (It is expected that replacement of the System32 one is already protected, to some degree, by being owned by the SYSTEM account and requiring some measure of authority to replace.)
@@ -242,8 +242,8 @@ I expect to take some degree of performance, power, and efficiency hit by implem
The mitigations to these losses are as follows:
1. We will delay load any of the interface load and packaging data lookup libraries to only be pulled into process space should we determine that the application is non-interactive.
1. That should save us some of the commit and power costs for the sorts of non-interactive scripts and applications that typically run early in OS startup (and leverage `conhost.exe` as their host environment).
1. We will delay load any of the interface load and packaging data lookup libraries to only be pulled into process space should we determine that the application is non-interactive.
1. That should save us some of the commit and power costs for the sorts of non-interactive scripts and applications that typically run early in OS startup (and leverage `conhost.exe` as their host environment).
1. We will still likely get hit with the on-disk commit cost for the additional export libraries linked as well as additional code. That would be a by-design change.
1. We plan to begin Profile Guided Optimization across our `OpenConsole.exe` and `WindowsTerminal.exe` binaries. This should allow us to optimize the startup paths for this scenario and bias the `OpenConsole.exe` binary that we redistribute to focus its efforts and efficiency on the ConPTY role specifically, ignoring all of the interactive Win32/GDI portions that aren't typically used.

View File

@@ -109,7 +109,7 @@ each thing in the elevated window that they'd want to create it elevated. Or the
Terminal would need to provide some setting like
`"autoElevateEverythingInAnElevatedWindow"`.
We cannot support mixed elevation when starting in a unelevated window.
We cannot support mixed elevation when starting in an unelevated window.
Therefore, it doesn't make a lot of UX sense to support it in the other
direction. It's a cleaner UX story to just have everything in a single window at
the same elevation level.
@@ -141,7 +141,7 @@ We could also simplify this to only allow a boolean true/false for displaying
the shield. As we do often with other enums, we could define `true` to be the
same as the default appearance, and `false` to be the hidden option. As always,
the development of the Terminal is an iterative process, where we can
incrementally improve from no setting, to a boolean setting, to a enum-backed
incrementally improve from no setting, to a boolean setting, to an enum-backed
one.
### Configuring a profile to always run elevated

View File

@@ -469,7 +469,7 @@ This is a list of actionable tasks generated as described by this spec:
commandline
* [ ] Add a `NameWindow` action, subcommand that allows the user to set the name
for the window.
* [ ] Add an action that will cause all windows to briefly display a overlay
* [ ] Add an action that will cause all windows to briefly display an overlay
with the current window ID and name. This would be something like the
"identify" feature of the Windows "Display" settings.

View File

@@ -886,7 +886,7 @@ Here, we've got two tabs that have been serialized.
- The second pane is also a `TermControl`, takes up 70% of the parent, and is
attached to the content process `{2-2-2-2}`
* The second tab has a single pane, with a SettingsPage. The settings page has
also specified in it's `payload` that its current page is the "globals" page.
also specified in its `payload` that its current page is the "globals" page.
When we send this serialized state to another window, it can use the content
GUIDs to initialize new `TermControl`s connected to the appropriate content
@@ -983,7 +983,7 @@ of each other.
all the logic concerning input. The core will expose these methods that the
UI layer calls as projected methods
8. (Dependent on 7): Expose the methods the UI layer calls on the core as
8. (Dependent on 7): Expose the methods that the UI layer calls on the core as
projected methods. The control is still fundamentally in-proc, and the UI
layer calls directly into the implementation of the control core, but the
methods _could_ be used x-proc.
@@ -1132,7 +1132,7 @@ prompt the user for permission, but that's an acceptable user experience.
## TODOs
* [x] Experimentally prove that a elevated window can host an unelevated content
* [x] Experimentally prove that an elevated window can host an unelevated content
- Research proved the opposite actually.
* [ ] Experimentally prove that I can toss content process IDs from one window
to another
@@ -1155,7 +1155,7 @@ prompt the user for permission, but that's an acceptable user experience.
## Addenda
This spec also has a follow-up spec which introduces further changes upon this
original draft. Please also refer to:
original draft. Please refer to:
* November 2020: Windows Terminal Window Management

View File

@@ -156,7 +156,7 @@ then this is the pane with the currently focused terminal control. When the user
brings the tab into focus, the last focused pane is the pane that should become
focused again.
The tab's state will be updated to reflect the state of it's focused pane. The
The tab's state will be updated to reflect the state of its focused pane. The
title text and icon of the tab will reflect that of the focused pane. Should the
focus switch from one pane to another, the tab's text and icon should update to
reflect the newly focused control. Any additional state that the tab would
@@ -172,7 +172,7 @@ match.
A pane can either be closed by the user manually, or when the terminal it's
attached to raises its ConnectionClosed event. When this happens, we should
remove this pane from the tree. The parent of the closing pane will have to
remove the pane as one of it's children. If the sibling of the closing pane is a
remove the pane as one of its children. If the sibling of the closing pane is a
leaf, then the parent should just take all of the state from the remaining pane.
This will cause the remaining pane's content to expand to take the entire
boundaries of the parent's pane. If the remaining child was a parent itself,
@@ -182,7 +182,7 @@ replaced by the remaining child.
## Future considerations
The Pane implementation isn't complete in it's current form. There are many
The Pane implementation isn't complete in its current form. There are many
additional things that could be done to improve the user experience. This is by
no means a comprehensive list.

View File

@@ -30,7 +30,7 @@ Conhost already has a module for search. It implements case-sensitive or insensi
We will create a `SearchBoxControl` Xaml `UserControl` element. When a search process begins, a `SearchBoxControl` object will be created and attached to `TermControl` root grid. In other words, one SearchBox is added for each `TermControl`. The reasons for this design is:
1. Each `TermControl` object is a Terminal Window and has a individual text buffer. In phase 1 we are going to search within the current terminal text buffer.
1. Each `TermControl` object is a Terminal Window and has an individual text buffer. In phase 1 we are going to search within the current terminal text buffer.
2. If we put the search box under TerminalApp, then the search can only happen on the current focused Terminal.
3. If the community does not like the current design, we can lift SearchBox to a higher level.
@@ -55,7 +55,7 @@ Above is the `SearchBoxControl` in dark theme and light theme.
![SearchBox mockup, arrow button clicked](images/SearchBoxUpSelected.png)
The search box defaults to be on the top right corner of the Terminal window. If the current tab is split into panes, each pane will have a individual searchbox.
The search box defaults to the top right corner of the Terminal window. If the current tab is split into panes, each pane will have an individual searchbox.
#### Search process
1. The user presses <kbd>ctrl+shift+f</kbd> (or user's custom key binding) to open the search box. Focus will move to the TextBox.

View File

@@ -169,7 +169,7 @@ wt my-commandline.exe with some args
# tab, and in another tab, run "another.exe running in a second tab"
wt my-commandline.exe with some args and a \; literal semicolon ; new-tab another.exe running in a second tab
# Start cmd.exe, then split it vertically (with the first taking 70% of it's
# Start cmd.exe, then split it vertically (with the first taking 70% of its
# space, and the new pane taking 30%), and run wsl.exe in that pane (user story 13)
wt cmd.exe ; split-pane --target 0 -V -% 30 wsl.exe
wt cmd.exe ; split-pane -% 30 wsl.exe
@@ -551,7 +551,7 @@ this works as expected.
Painfully, powershell uses `;` as a separator between commands as well. So, if
someone wanted to call a `wt` commandline in powershell with multiple commands,
the user would need to also escape those semicolons for powershell first. That
the user would also need to escape those semicolons for powershell first. That
means a command like ```wt new-tab ; split-pane``` would need to be ```wt new-tab
`; split-pane``` in powershell, and ```wt new-tab ; split-pane commandline \; with
\; semicolons``` would need to become ```wt new-tab `; split-pane commandline \`;

View File

@@ -69,7 +69,7 @@ To implement this feature, we'll add the following settings:
### `globalSummon` Action
The `globalSummon` action will be a keybinding the user can use to summon a
The `globalSummon` action will be a keybinding that the user can use to summon a
Terminal window from anywhere in the OS. Various arguments to the action will
specify which window is summoned, to where, and how the window should behave on
summon.
@@ -182,7 +182,7 @@ for pure markdown, sorry. -->
<tr>
<td><code>"any"</code><br> Summon the MRU window</td>
<td>Go to the desktop the window is on (leave position alone)</td>
<td>Go to the desktop with the window (leave position alone)</td>
<td>Move the window to this desktop (leave position alone)</td>
<td>
@@ -196,7 +196,7 @@ Else:
<!-- ----------------------------------------------------------------------- -->
<tr>
<td><code>"toCurrent"</code><br> Summon the MRU window TO the monitor with the foreground window</td>
<td>Go to the desktop the window is on, move to the monitor with the foreground window</td>
<td>Go to the desktop with the window, move to the monitor with the foreground window</td>
<td>Move the window to this desktop, move to the monitor with the foreground window</td>
<td>
@@ -213,7 +213,7 @@ Else:
<code>"toMouse"</code>
<sup><a href="#footnote-2">[2]</a></sup> <br>
Summon the MRU window TO the monitor with the mouse</td>
<td>Go to the desktop the window is on, move to the monitor with the mouse</td>
<td>Go to the desktop with the window, move to the monitor with the mouse</td>
<td>Move the window to this desktop, move to the monitor with the mouse</td>
<td>
@@ -230,7 +230,7 @@ Else:
<td>
If there is a window on this monitor on any desktop,
* Go to the desktop the window is on (leave position alone)
* Go to the desktop with the window (leave position alone)
else
* Create a new window on this monitor & desktop
@@ -262,7 +262,7 @@ Else (one on this desktop & monitor)
<td>
If there is a window on monitor N on any desktop,
* Go to the desktop the window is on (leave position alone)
* Go to the desktop with the window (leave position alone)
else
* Create a new window on this monitor & desktop

View File

@@ -273,7 +273,7 @@ with GUIDs set.
After a dynamic profile generator runs, we will determine what new profiles need
to be added to the user settings, so we can append those to the list of
profiles. The deserializer will look at the list of generated profiles and check
if each and every one already has a entry in the user settings. The generator
if each and every one already has an entry in the user settings. The generator
will just blind hand back a list of profiles, and the deserializer will figure
out if any of them need to be added to the user settings. We'll store some sort
of result indicating that we want a save operation to occur. After the rest of
@@ -505,8 +505,8 @@ like so:
// To view the default settings, open the defaults.json file in this directory
```
The "Settings" button would then only open the file the user needs to edit, and
provide them instructions on how to open the defaults file.
The "Settings" button would then only open the file that the user needs to edit,
and provide them instructions on how to open the defaults file.
There could alternatively be a hidden option for the "Open Settings" button,
where holding <kbd>Alt</kbd> while clicking on the button would open the

View File

@@ -56,7 +56,7 @@ short duration after they're made.
## UI/UX Design
This has no direct impact on the UI/UX; however, we may want to add a button to general settings page titled "reset all
dialogs" or "don't not ask me again about those things that, some time ago, I told you to not ask me about".
dialogs" or "ask me *again* about those things that, some time ago, I told you to not ask me about".
We do not intend this file to be edited by hand, so it does not have to be user-friendly or serialized with indentation.

View File

@@ -66,7 +66,7 @@ default profiles (cmd/powershell) or the dynamically generated profiles.
For modifications to existing profiles, the json stub would need to indicate which profile it wishes to modify. It will
do this by providing the corresponding guid in the `"updates"` field of the json stub. The reason we use an `"updates"`
field rather than a `"guid"` field (like the way the user settings are eventually layered onto profiles) is because we
field rather than a `"guid"` field (like the way that user settings are eventually layered onto profiles) is because we
do not want to mistakenly create a new profile when the stub was meant to update a profile that did not exist.
Note that currently, we generate a GUID for dynamic profiles using the "initial" name of the profile (i.e. before
@@ -96,7 +96,7 @@ Here is an example of a json file that modifies an existing profile (specificall
}
```
**NOTE**: This will *not* change the way the profile looks in the user's settings file. The Azure cloud shell profile
**NOTE**: This will *not* change the way that profile looks in the user's settings file. The Azure cloud shell profile
in their settings file (assuming they have made no changes) will still be as below.
```js

View File

@@ -31,7 +31,7 @@ There are several common pieces needed for both the tab tear-off scenario and th
We need some sort of server/manager code that sits there waiting for connections from `wt.exe` processes and potentially `conhost.exe` processes such that it can broker a connection between the processes. It either needs to run in its own process or it needs to run in one of the existing `wt.exe`s that is chosen as the primary manager at the time. It should create communication channels and a global mutex at the time of creation.
All other `wt.exe` processes starting after the primary should detect the existence of the server manager process and wait on the mutex handle. When the primary disappears, the OS scheduler should choose one of the others to wake up first on the mutex. It can take the lock and then set up the primary management channel.
All other `wt.exe` processes starting after the primary should detect the existence of the server manager process and wait on the mutex handle. When the primary disappears, the OS scheduler should choose one of the others to wake up first on the mutex. It can take the lock and then set up the primary management channel.
Alternatively, if the manager process is completely isolated and we expect all `wt.exe`s to have to remain connected at all times, we can make it such that when the connections are broken between the individual processes and the manager that they all shut down. I would prefer that it is resilient (the previous option) over this one, but browsers must have a good reason for preferring this way.
@@ -85,7 +85,7 @@ If the registered handler fails to start the connection, there is no registered
##### Interactive vs. Not
We would have to be able to detect the difference between an interactive and non-interactive mode here.
We would have to be able to detect the difference between an interactive and non-interactive mode here.
- Interactive is defined as the end-user is attempting to launch a command-line application with a visible window to see the output and enter input.
- Non-interactive is defined as tools, utilities, and services attempting to launch a command-line application with no visible window (and possibly some redirected handles).
@@ -120,7 +120,7 @@ There's a few areas to study here.
3. Updating conhost.exe to look up the launch preference and/or to launch another console host via a protocol handler
- This would allow the `C:\windows\system32\conhost.exe` to effectively delegate the session to another `conhost.exe` that is hopefully newer than the inbox one. Given that the driver protocol in the box doesn't change and hasn't changed and we don't intend to change it, the forward/backward compatibility story is great here. Additionally, if for whatever reason the delegated `conhost.exe` fails to launch, we can just fall back and launch the old one like we would have prior to the change. It is significantly more likely, but still challenging, to argue for servicing `conhost.exe` back several versions in Windows to make this light up better for all folks. It might be especially more possible if it is a very targeted code snippet that can drop in to all the old versions of the `conhost.exe` code. We would still have the argument about spending resources developing for OS versions that are supposed to be dropped in favor of latest, but it's still a lesser argument than upending all of `kernelbase.dll`.
- A protocol handler is also well understood and relatively well handled/tested in Windows. Old apps can handle protocols. New apps can handle protocols. Protocol handlers can take arguments. We don't have to lean on any other team to get them to help change the way the rest of the OS works.
- A protocol handler is also well understood and relatively well handled/tested in Windows. Old apps can handle protocols. New apps can handle protocols. Protocol handlers can take arguments. We don't have to lean on any other team to get them to help change the way that the rest of the OS works.
#### Communicating the launch
For the parameters passing, I see a few options:
@@ -149,7 +149,7 @@ To simplify this for a first iteration, we could just make it so the transfer do
- If released onto anything that isn't a `wt.exe` instance, we create a new `wt.exe` instance and send in the connection as the default startup parameter.
#### Component UI
It is also theoretically possible that if we could find a Component UI style solution (where the tab/panes live in their own process and just remote the UI/input into the shell) that it would be easy and even trivial to change out which shell/frame host is holding that element at any given time.
It is also theoretically possible that if we could find a Component UI style solution (where the tab/panes live in their own process and just remote the UI/input into the shell) that it would be easy and even trivial to change out which shell/frame host is holding that element at any given time.
### For Default Application
The UX would make it look exactly like the user had started `wt.exe` from a shortcut or launch tile, but would launch the first tab differently than the defaults.
@@ -173,7 +173,7 @@ I don't believe it changes anything for accessibility. The only concern I'd have
This particular feature will have to go through a security review/audit. It is unclear what level of control we will need over the IPC communication channels. A few things come to mind:
1. We need to ensure that the mutexes/pipes/communications are restricted inside of one particular session to one particular user. If another user is also running WT in their session, it should involve a completely different manager process and system objects.
1. We MAY have to enforce a scenario where we inhibit cross-integrity-level connections from being passed around. Generally speaking, processes at a higher integrity level have the authority to perform actions on those with a lower integrity level. This means that an elevated `wt.exe` could theoretically send a tab to a standard level `wt.exe`. We may be required to inhibit/prohibit this. We may also need to have one manager per integrity level.
1. We MAY have to enforce a scenario where we inhibit cross-integrity-level connections from being passed around. Generally speaking, processes at a higher integrity level have the authority to perform actions on those with a lower integrity level. This means that an elevated `wt.exe` could theoretically send a tab to a standard level `wt.exe`. We may be required to inhibit/prohibit this. We may also need to have one manager per integrity level.
1. I'm not sure what sorts of ACL/DACL/SACLs we would need to apply to all the kernel objects involved.
1. My initial prototype here used message-passing type pipes with a custom rolled protocol. If I make my own protocol, it needs to be fuzzed. And I'm probably missing something. Many/most of these concerns for security are probably eliminated if we use a well-known mechanism for this sort of IPC. My thoughts go to a COM server. More complicated to implement than message pipes, but probably brings a lot of security benefits and eliminates the need to fuzz the protocol (probably).
@@ -184,18 +184,18 @@ In the simple implementation, it will decrease reliability. We'll be shuffling c
We might be able to mitigate some of the reliability concerns here or even improve reliability by going a step further with the process/containerization model like browsers do and standing up each individual tab as its own process host.
```
wt.exe - Manager Mode
|- wt.exe - Frame Host Mode
wt.exe - Manager Mode
|- wt.exe - Frame Host Mode
| |- wt.exe - Tab Host Mode
| | |- conhost.exe - ConPTY mode
| | |- pwsh.exe - Client application
| | |- pwsh.exe - Client application
| |- wt.exe - Tab Host Mode
| |- conhost.exe - ConPTY mode
| |- cmd.exe - Client application
|- wt.exe - Frame Host Mode
| |- cmd.exe - Client application
|- wt.exe - Frame Host Mode
|- wt.exe - Tab Host Mode
|- conhost.exe - ConPTY mode
|- pwsh.exe - Client application
|- pwsh.exe - Client application
```
The current structure of `wt.exe` has everything hosted within the one process. To improve reliability, we would likely have to make `wt.exe` run in three modes.
@@ -219,29 +219,29 @@ It is possible (but would need to be explored) that the APIs available to us to
In the one instance, we have this process hierarchy. Two instances of Windows Terminal exist. In Terminal A, the user has started a `cmd.exe` and a `pwsh.exe` tab. In the second instance, the user has started just one `cmd.exe` tab.
```
- wt.exe (Terminal Instance A)
- wt.exe (Terminal Instance A)
|- conhost.exe (in PTY mode) - Hosted to A
| |- cmd.exe
|- conhost.exe (in PTY mode) - Hosted to A
|- pwsh.exe <-- I will be dragged out
- wt.exe (Terminal Instance B)
|- conhost.exe (in PTY mode) - Hosted to B
|- cmd.exe
|- conhost.exe (in PTY mode) - Hosted to B
|- cmd.exe
```
When the `pwsh.exe` tab is torn off from Instance A and is dropped onto Instance B, the process hierarchy doesn't actually change. The connection details, preferences, and session metadata are passed via the IPC management channels, but to an outside observer, nothing has actually changed.
```
- wt.exe (Terminal Instance A)
- wt.exe (Terminal Instance A)
|- conhost.exe (in PTY mode) - Hosted to A
| |- cmd.exe
|- conhost.exe (in PTY mode) - Hosted to B
|- pwsh.exe <-- I am hosted in B but I'm parented to A
- wt.exe (Terminal Instance B)
|- conhost.exe (in PTY mode) - Hosted to B
|- cmd.exe
|- conhost.exe (in PTY mode) - Hosted to B
|- cmd.exe
```
I don't believe there are provisions in the Windows OS to reparent applications to a different process.
@@ -253,8 +253,8 @@ Additionally, this becomes more interesting when Terminal Instance A dies and B
|- pwsh.exe <-- I am hosted in B but I'm parented to A
- wt.exe (Terminal Instance B)
|- conhost.exe (in PTY mode) - Hosted to B
|- cmd.exe
|- conhost.exe (in PTY mode) - Hosted to B
|- cmd.exe
```
When instance A dies, the `conhost.exe` that was reparented keeps running and now just appears orphaned within the process hierarchy, reporting to the top level under utilities like Process Explorer.
@@ -280,7 +280,7 @@ The `conhost.exe` was started in response to a `pwsh.exe` being started with no
```
- conhost.exe - idling
- wt.exe (Terminal Instance A)
|- conhost.exe (in PTY mode)
|- pwsh.exe
@@ -294,7 +294,7 @@ This is obviously less efficient than not doing it as we have to stand up server
But as long as we're creating threads and services that sleep most of the time and are only awakened on some kernel/system event, we shouldn't be wasting too much in terms of power and background resources.
Additionally, `wt.exe` is worse than `conhost.exe` alone in all efficiency categories simply because it not only requires more resources to display in a "pretty" manner, but it also requires a `conhost.exe` under it in PTY mode to adapt the API calls. This is generally acceptable for end users who care more about the experience than the total performance.
Additionally, `wt.exe` is worse than `conhost.exe` alone in all efficiency categories simply because it not only requires more resources to display in a "pretty" manner, but it also requires a `conhost.exe` under it in PTY mode to adapt the API calls. This is generally acceptable for end users who care more about the experience than the total performance.
It is, however, not likely to be much if any worse than just choosing to use `wt.exe` anyway over `conhost.exe`.
@@ -304,7 +304,7 @@ I've listed most of the issues above in their individual sections. The primary h
1. Process tree layout - The processes in hierarchy may not make sense to someone inspecting them either visually with a tool or programmatically
1. Process and kernel object lifetime - Applications may be counting on a specific process or object lifetime in regards to their hosting window and we might be tampering with that in how we apply job objects or shuffle around ownership to make tabs happen
1. Default launch expectations - It is possible that test utilities or automation are counting on `conhost.exe` being the host application or that they're not ready to tolerate the potential for other applications to start. I think the interactive/non-interactive check mitigates this, but we'd have to remain concerned here.
1. `AttachConsole` and `DetachConsole` and `AllocConsole` - I don't have the slightest idea what happens for these APIs. We would have to explore. `AttachConsole` has restrictions based on the process hierarchy. It would likely behave in interesting ways with the strange parenting order and might be a driver to why we would have to adjust the parenting of the processes (or change the API under the hood). `DetachConsole` might create an issue where a tab disappears out of the terminal and the job object causes everything to die. `AttachConsole` wouldn't necessarily be guaranteed to go back into the same `wt.exe` or a `wt.exe` at all.
1. `AttachConsole` and `DetachConsole` and `AllocConsole` - I don't have the slightest idea what happens for these APIs. We would have to explore. `AttachConsole` has restrictions based on the process hierarchy. It would likely behave in interesting ways with the strange parenting order and might be a driver to why we would have to adjust the parenting of the processes (or change the API under the hood). `DetachConsole` might create an issue where a tab disappears out of the terminal and the job object causes everything to die. `AttachConsole` wouldn't necessarily be guaranteed to go back into the same `wt.exe` or a `wt.exe` at all.
## Future considerations

View File

@@ -647,7 +647,7 @@ style admin vs regular windows?
## Addenda
This spec also has a follow-up spec which elaborates on the complexities of Mica
in the Terminal. Please also refer to:
in the Terminal. Please refer to:
* [Mica in the Terminal]

View File

@@ -94,7 +94,7 @@ should the control provide some sort of accessibility pattern.
if the hosted control wants to use Ctrl+T for its own shortcut? The current
keybindings model has the `TermControl` call into the App layer to see if a
keystroke should be handled by the app first. We may want to make sure that
for non-terminal controls, we add a event handler to try and have the
for non-terminal controls, we add an event handler to try and have the
`AppKeyBindings` handle the keypress if the control doesn't. This won't solve
the case where the control wants to use a keybinding that is mapped by the
Terminal App. In that case, non-terminal controls will actually behave

View File

@@ -350,7 +350,7 @@ void ROW::_init() noexcept
std::iota(_charOffsets.begin(), _charOffsets.end(), uint16_t{ 0 });
#endif
#pragma warning(push)
#pragma warning(pop)
}
void ROW::CopyFrom(const ROW& source)
@@ -1143,6 +1143,13 @@ til::CoordType ROW::GetTrailingColumnAtCharOffset(const ptrdiff_t offset) const
return _createCharToColumnMapper(offset).GetTrailingColumnAt(offset);
}
uint16_t ROW::GetCharOffset(til::CoordType col) const noexcept
{
const auto columns = GetReadableColumnCount();
const auto colBeg = clamp(col, 0, columns);
return _uncheckedCharOffset(gsl::narrow_cast<size_t>(colBeg));
}
DelimiterClass ROW::DelimiterClassAt(til::CoordType column, const std::wstring_view& wordDelimiters) const noexcept
{
const auto col = _clampedColumn(column);

View File

@@ -172,6 +172,7 @@ public:
std::wstring_view GetText(til::CoordType columnBegin, til::CoordType columnEnd) const noexcept;
til::CoordType GetLeadingColumnAtCharOffset(ptrdiff_t offset) const noexcept;
til::CoordType GetTrailingColumnAtCharOffset(ptrdiff_t offset) const noexcept;
uint16_t GetCharOffset(til::CoordType col) const noexcept;
DelimiterClass DelimiterClassAt(til::CoordType column, const std::wstring_view& wordDelimiters) const noexcept;
auto AttrBegin() const noexcept { return _attr.begin(); }

View File

@@ -100,7 +100,7 @@ void TextBuffer::_reserve(til::size screenBufferSize, const TextAttribute& defau
const auto rowStride = rowSize + charsBufferSize + charOffsetsBufferSize;
assert(rowStride % alignof(ROW) == 0);
// 65535*65535 cells would result in a allocSize of 8GiB.
// 65535*65535 cells would result in an allocSize of 8GiB.
// --> Use uint64_t so that we can safely do our calculations even on x86.
// We allocate 1 additional row, which will be used for GetScratchpadRow().
const auto rowCount = ::base::strict_cast<uint64_t>(h) + 1;
@@ -219,6 +219,17 @@ til::CoordType TextBuffer::_estimateOffsetOfLastCommittedRow() const noexcept
return std::max(0, gsl::narrow_cast<til::CoordType>(lastRowOffset - 2));
}
bool TextBuffer::_isRowCommitted(til::CoordType y) const noexcept
{
auto offset = (_firstRow + y + 1 /* account for the scratch row */) % _height;
if (offset < 0)
{
offset += _height;
}
const auto row = _buffer.get() + _bufferRowStride * offset;
return row < _commitWatermark;
}
// Retrieves a row from the buffer by its offset from the first row of the text buffer
// (what corresponds to the top row of the screen buffer).
const ROW& TextBuffer::GetRowByOffset(const til::CoordType index) const
@@ -934,6 +945,10 @@ void TextBuffer::ResetLineRenditionRange(const til::CoordType startRow, const ti
LineRendition TextBuffer::GetLineRendition(const til::CoordType row) const
{
if (!_isRowCommitted(row)) [[unlikely]]
{
return LineRendition::SingleWidth;
}
return GetRowByOffset(row).GetLineRendition();
}
@@ -1141,7 +1156,20 @@ DelimiterClass TextBuffer::_GetDelimiterClassAt(const til::point pos, const std:
return GetRowByOffset(realPos.y).DelimiterClassAt(realPos.x, wordDelimiters);
}
til::point TextBuffer::GetWordStart2(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional) const
// Method Description:
// - Get the start of the word at or before the given position
// - When includeWhitespace is false, returns the start of the current delimiter class run
// (selection behavior: stops at non-wrapped row boundaries)
// - When includeWhitespace is true, also skips backward past any leading ControlChars
// to include the preceding word (accessibility/UIA behavior: crosses all row boundaries)
// Arguments:
// - pos - the buffer position to start from
// - wordDelimiters - characters considered as DelimiterClass::DelimiterChar
// - includeWhitespace - when true, skip past leading whitespace to find the word start
// - limitOptional - (optional) the last possible position in the buffer that can be explored
// Return Value:
// - The position of the first character of the word (inclusive)
til::point TextBuffer::GetWordStart(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional) const
{
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.BottomInclusiveRightExclusive()) };
@@ -1174,7 +1202,7 @@ til::point TextBuffer::GetWordStart2(til::point pos, const std::wstring_view wor
// 1. move to the beginning of the delimiter class run
// 2. (includeWhitespace) if we were on a ControlChar, go back one more delimiter class run
const auto initialDelimiter = bufferSize.IsInBounds(pos) ? _GetDelimiterClassAt(pos, wordDelimiters) : DelimiterClass::ControlChar;
pos = _GetDelimiterClassRunStart(pos, wordDelimiters);
pos = _GetDelimiterClassRunStart(pos, wordDelimiters, includeWhitespace);
if (!includeWhitespace || pos.x == bufferSize.Left())
{
// Special case:
@@ -1185,12 +1213,26 @@ til::point TextBuffer::GetWordStart2(til::point pos, const std::wstring_view wor
else if (initialDelimiter == DelimiterClass::ControlChar)
{
bufferSize.DecrementInExclusiveBounds(pos);
pos = _GetDelimiterClassRunStart(pos, wordDelimiters);
pos = _GetDelimiterClassRunStart(pos, wordDelimiters, includeWhitespace);
}
return pos;
}
til::point TextBuffer::GetWordEnd2(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional) const
// Method Description:
// - Get the exclusive end of the word at or after the given position
// - When includeWhitespace is false, returns the exclusive end of the current delimiter class run
// (selection behavior: stops at non-wrapped row boundaries)
// - When includeWhitespace is true, also skips forward past any trailing ControlChars
// to include trailing whitespace (accessibility/UIA behavior: crosses all row boundaries)
// - The result is clamped to limitOptional when provided
// Arguments:
// - pos - the buffer position to start from
// - wordDelimiters - characters considered as DelimiterClass::DelimiterChar
// - includeWhitespace - when true, skip past trailing whitespace to find the next word boundary
// - limitOptional - (optional) the last possible position in the buffer that can be explored
// Return Value:
// - The exclusive end position of the word
til::point TextBuffer::GetWordEnd(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional) const
{
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.BottomInclusiveRightExclusive()) };
@@ -1223,8 +1265,12 @@ til::point TextBuffer::GetWordEnd2(til::point pos, const std::wstring_view wordD
// So the heuristic we use is:
// 1. move to the end of the delimiter class run
// 2. (includeWhitespace) if the next delimiter class run is a ControlChar, go forward one more delimiter class run
pos = _GetDelimiterClassRunEnd(pos, wordDelimiters);
if (!includeWhitespace || pos.x == bufferSize.RightExclusive())
pos = _GetDelimiterClassRunEnd(pos, wordDelimiters, includeWhitespace);
if (pos >= limit)
{
return limit;
}
else if (!includeWhitespace || pos.x == bufferSize.RightExclusive())
{
// Special case:
// we're at the right boundary (and end of a delimiter class run),
@@ -1235,7 +1281,8 @@ til::point TextBuffer::GetWordEnd2(til::point pos, const std::wstring_view wordD
if (const auto nextDelimClass = bufferSize.IsInBounds(pos) ? _GetDelimiterClassAt(pos, wordDelimiters) : DelimiterClass::ControlChar;
nextDelimClass == DelimiterClass::ControlChar)
{
return _GetDelimiterClassRunEnd(pos, wordDelimiters);
pos = _GetDelimiterClassRunEnd(pos, wordDelimiters, includeWhitespace);
return std::min(pos, limit);
}
return pos;
}
@@ -1288,29 +1335,48 @@ bool TextBuffer::IsWordBoundary(const til::point pos, const std::wstring_view wo
return prevDelimiterClass != currentDelimiterClass && currentDelimiterClass != DelimiterClass::ControlChar;
}
til::point TextBuffer::_GetDelimiterClassRunStart(til::point pos, const std::wstring_view wordDelimiters) const
// Method Description:
// - Get the start position for the current delimiter class run, scanning backward
// - Stops when the delimiter class changes or a row boundary is reached
// - When accessibilityMode is true, freely crosses non-wrapped row boundaries
// - When accessibilityMode is false, only crosses wrap-forced row boundaries
// Arguments:
// - pos - the buffer position to start scanning from
// - wordDelimiters - what characters are we considering for the separation of words
// - accessibilityMode - when true, cross non-wrapped row boundaries freely
// Return Value:
// - The position of the first character in the current delimiter class run (inclusive)
til::point TextBuffer::_GetDelimiterClassRunStart(til::point pos, const std::wstring_view wordDelimiters, const bool accessibilityMode) const
{
const auto bufferSize = GetSize();
const auto initialDelimClass = bufferSize.IsInBounds(pos) ? _GetDelimiterClassAt(pos, wordDelimiters) : DelimiterClass::ControlChar;
for (auto nextPos = pos; nextPos != bufferSize.Origin(); pos = nextPos)
auto nextPos = pos;
while (nextPos != bufferSize.Origin())
{
bufferSize.DecrementInExclusiveBounds(nextPos);
if (nextPos.x == bufferSize.RightExclusive())
{
// wrapped onto previous line,
// check if it was forced to wrap
// wrapped onto previous line
const auto& row = GetRowByOffset(nextPos.y);
if (!row.WasWrapForced())
if (!row.WasWrapForced() && !accessibilityMode)
{
return pos;
}
// In accessibility mode (or if row was wrap-forced), continue
// across the row boundary. The actual last character of the
// previous row will be checked on the next iteration.
// Don't update pos to avoid storing a transient position
}
else if (_GetDelimiterClassAt(nextPos, wordDelimiters) != initialDelimClass)
{
// if we changed delim class, we're done (don't apply move)
return pos;
}
else
{
pos = nextPos;
}
}
return pos;
}
@@ -1320,7 +1386,8 @@ til::point TextBuffer::_GetDelimiterClassRunStart(til::point pos, const std::wst
// Arguments:
// - pos - the buffer position being within the current delimiter class
// - wordDelimiters - what characters are we considering for the separation of words
til::point TextBuffer::_GetDelimiterClassRunEnd(til::point pos, const std::wstring_view wordDelimiters) const
// - accessibilityMode - when true, cross non-wrapped row boundaries freely
til::point TextBuffer::_GetDelimiterClassRunEnd(til::point pos, const std::wstring_view wordDelimiters, const bool accessibilityMode) const
{
const auto bufferSize = GetSize();
const auto initialDelimClass = bufferSize.IsInBounds(pos) ? _GetDelimiterClassAt(pos, wordDelimiters) : DelimiterClass::ControlChar;
@@ -1333,7 +1400,16 @@ til::point TextBuffer::_GetDelimiterClassRunEnd(til::point pos, const std::wstri
// wrapped onto next line,
// check if it was forced to wrap or switched delimiter class
const auto& row = GetRowByOffset(pos.y);
if (!row.WasWrapForced() || _GetDelimiterClassAt(nextPos, wordDelimiters) != initialDelimClass)
if (accessibilityMode)
{
// In accessibility mode, always cross row boundaries,
// but still stop if the delimiter class changes
if (_GetDelimiterClassAt(nextPos, wordDelimiters) != initialDelimClass)
{
return nextPos;
}
}
else if (!row.WasWrapForced() || _GetDelimiterClassAt(nextPos, wordDelimiters) != initialDelimClass)
{
return pos;
}
@@ -1348,283 +1424,6 @@ til::point TextBuffer::_GetDelimiterClassRunEnd(til::point pos, const std::wstri
return pos;
}
// Method Description:
// - Get the til::point for the beginning of the word you are on
// Arguments:
// - target - a til::point on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// - accessibilityMode - when enabled, we continue expanding left until we are at the beginning of a readable word.
// Otherwise, expand left until a character of a new delimiter class is found
// (or a row boundary is encountered)
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value:
// - The til::point for the first character on the "word" (inclusive)
til::point TextBuffer::GetWordStart(const til::point target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
{
// Consider a buffer with this text in it:
// " word other "
// In selection (accessibilityMode = false),
// a "word" is defined as the range between two delimiters
// so the words in the example include [" ", "word", " ", "other", " "]
// In accessibility (accessibilityMode = true),
// a "word" includes the delimiters after a range of readable characters
// so the words in the example include ["word ", "other "]
// NOTE: the start anchor (this one) is inclusive, whereas the end anchor (GetWordEnd) is exclusive
#pragma warning(suppress : 26496)
auto copy{ target };
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (target == bufferSize.Origin())
{
// can't expand left
return target;
}
else if (target == bufferSize.EndExclusive())
{
// GH#7664: Treat EndExclusive as EndInclusive so
// that it actually points to a space in the buffer
copy = bufferSize.BottomRightInclusive();
}
else if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
// if at/past the limit --> clamp to limit
copy = limitOptional.value_or(bufferSize.BottomRightInclusive());
}
if (accessibilityMode)
{
return _GetWordStartForAccessibility(copy, wordDelimiters);
}
else
{
return _GetWordStartForSelection(copy, wordDelimiters);
}
}
// Method Description:
// - Helper method for GetWordStart(). Get the til::point for the beginning of the word (accessibility definition) you are on
// Arguments:
// - target - a til::point on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// Return Value:
// - The til::point for the first character on the current/previous READABLE "word" (inclusive)
til::point TextBuffer::_GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const
{
auto result = target;
const auto bufferSize = GetSize();
// ignore left boundary. Continue until readable text found
while (_GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
{
if (result == bufferSize.Origin())
{
//looped around and hit origin (no word between origin and target)
return result;
}
bufferSize.DecrementInBounds(result);
}
// make sure we expand to the left boundary or the beginning of the word
while (_GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
{
if (result == bufferSize.Origin())
{
// first char in buffer is a RegularChar
// we can't move any further back
return result;
}
bufferSize.DecrementInBounds(result);
}
// move off of delimiter
bufferSize.IncrementInBounds(result);
return result;
}
// Method Description:
// - Helper method for GetWordStart(). Get the til::point for the beginning of the word (selection definition) you are on
// Arguments:
// - target - a til::point on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// Return Value:
// - The til::point for the first character on the current word or delimiter run (stopped by the left margin)
til::point TextBuffer::_GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const
{
auto result = target;
const auto bufferSize = GetSize();
const auto initialDelimiter = _GetDelimiterClassAt(result, wordDelimiters);
const bool isControlChar = initialDelimiter == DelimiterClass::ControlChar;
// expand left until we hit the left boundary or a different delimiter class
while (result != bufferSize.Origin() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
{
if (result.x == bufferSize.Left())
{
// Prevent wrapping to the previous line if the selection begins on whitespace
if (isControlChar)
{
break;
}
if (result.y > 0)
{
// Prevent wrapping to the previous line if it was hard-wrapped (e.g. not forced by us to wrap)
const auto& priorRow = GetRowByOffset(result.y - 1);
if (!priorRow.WasWrapForced())
{
break;
}
}
}
bufferSize.DecrementInBounds(result);
}
if (_GetDelimiterClassAt(result, wordDelimiters) != initialDelimiter)
{
// move off of delimiter
bufferSize.IncrementInBounds(result);
}
return result;
}
// Method Description:
// - Get the til::point for the beginning of the NEXT word
// Arguments:
// - target - a til::point on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// - accessibilityMode - when enabled, we continue expanding right until we are at the beginning of the next READABLE word
// Otherwise, expand right until a character of a new delimiter class is found
// (or a row boundary is encountered)
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value:
// - The til::point for the last character on the "word" (inclusive)
til::point TextBuffer::GetWordEnd(const til::point target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
{
// Consider a buffer with this text in it:
// " word other "
// In selection (accessibilityMode = false),
// a "word" is defined as the range between two delimiters
// so the words in the example include [" ", "word", " ", "other", " "]
// In accessibility (accessibilityMode = true),
// a "word" includes the delimiters after a range of readable characters
// so the words in the example include ["word ", "other "]
// NOTE: the end anchor (this one) is exclusive, whereas the start anchor (GetWordStart) is inclusive
// Already at/past the limit. Can't move forward.
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
return target;
}
if (accessibilityMode)
{
return _GetWordEndForAccessibility(target, wordDelimiters, limit);
}
else
{
return _GetWordEndForSelection(target, wordDelimiters);
}
}
// Method Description:
// - Helper method for GetWordEnd(). Get the til::point for the beginning of the next READABLE word
// Arguments:
// - target - a til::point on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// - limit - the last "valid" position in the text buffer (to improve performance)
// Return Value:
// - The til::point for the first character of the next readable "word". If no next word, return one past the end of the buffer
til::point TextBuffer::_GetWordEndForAccessibility(const til::point target, const std::wstring_view wordDelimiters, const til::point limit) const
{
const auto bufferSize{ GetSize() };
auto result{ target };
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
// if we're already on/past the last RegularChar,
// clamp result to that position
result = limit;
// make the result exclusive
bufferSize.IncrementInBounds(result, true);
}
else
{
while (result != limit && result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
{
// Iterate through readable text
bufferSize.IncrementInBounds(result);
}
while (result != limit && result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
{
// expand to the beginning of the NEXT word
bufferSize.IncrementInBounds(result);
}
// Special case: we tried to move one past the end of the buffer
// Manually increment onto the EndExclusive point.
if (result == bufferSize.BottomRightInclusive())
{
bufferSize.IncrementInBounds(result, true);
}
}
return result;
}
// Method Description:
// - Helper method for GetWordEnd(). Get the til::point for the beginning of the NEXT word
// Arguments:
// - target - a til::point on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// Return Value:
// - The til::point for the last character of the current word or delimiter run (stopped by right margin)
til::point TextBuffer::_GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const
{
const auto bufferSize = GetSize();
auto result = target;
const auto initialDelimiter = _GetDelimiterClassAt(result, wordDelimiters);
const bool isControlChar = initialDelimiter == DelimiterClass::ControlChar;
// expand right until we hit the right boundary as a ControlChar or a different delimiter class
while (result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
{
if (result.x == bufferSize.RightInclusive())
{
// Prevent wrapping to the next line if the selection begins on whitespace
if (isControlChar)
{
break;
}
// Prevent wrapping to the next line if this one was hard-wrapped (e.g. not forced by us to wrap)
const auto& row = GetRowByOffset(result.y);
if (!row.WasWrapForced())
{
break;
}
}
bufferSize.IncrementInBounds(result);
}
if (_GetDelimiterClassAt(result, wordDelimiters) != initialDelimiter)
{
// move off of delimiter
bufferSize.DecrementInBounds(result);
}
return result;
}
void TextBuffer::_PruneHyperlinks()
{
// Check the old first row for hyperlink references
@@ -1671,57 +1470,6 @@ void TextBuffer::_PruneHyperlinks()
}
}
// Method Description:
// - Update pos to be the position of the first character of the next word. This is used for accessibility
// Arguments:
// - pos - a til::point on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The til::point for the first character on the "word" (inclusive)
bool TextBuffer::MoveToNextWord(til::point& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional) const
{
// move to the beginning of the next word
// NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word"
// This is also the inclusive start of the next word.
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) };
if (bufferSize.CompareInBounds(copy, limit, true) >= 0)
{
return false;
}
pos = copy;
return true;
}
// Method Description:
// - Update pos to be the position of the first character of the previous word. This is used for accessibility
// Arguments:
// - pos - a til::point on the word you are currently on
// - wordDelimiters - what characters are we considering for the separation of words
// Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The til::point for the first character on the "word" (inclusive)
bool TextBuffer::MoveToPreviousWord(til::point& pos, std::wstring_view wordDelimiters) const
{
// move to the beginning of the current word
auto copy{ GetWordStart(pos, wordDelimiters, true) };
if (!GetSize().DecrementInBounds(copy, true))
{
// can't move behind current word
return false;
}
// move to the beginning of the previous word
pos = GetWordStart(copy, wordDelimiters, true);
return true;
}
// Method Description:
// - Update pos to be the beginning of the current glyph/character. This is used for accessibility
// Arguments:
@@ -2976,7 +2724,7 @@ void TextBuffer::Reflow(TextBuffer& oldBuffer, TextBuffer& newBuffer, const View
til::point newCursorPos;
// BODGY: We use oldCursorPos in two critical places below:
// * To compute an oldHeight that includes at a minimum the cursor row
// * To compute an oldHeight that includes, at a minimum, the cursor row
// * For REFLOW_JANK_CURSOR_WRAP (see comment below)
// Both of these would break the reflow algorithm, but the latter of the two in particular
// would cause the main copy loop below to deadlock. In other words, these two lines
@@ -3096,7 +2844,7 @@ void TextBuffer::Reflow(TextBuffer& oldBuffer, TextBuffer& newBuffer, const View
// We don't need to be smart about this. Reset() is fast and shrinking doesn't occur often.
if (newY >= newHeight && newX == 0)
{
// We need to ensure not to overwrite the row the cursor is on.
// We need to ensure not to overwrite the row containing the cursor.
if (newY >= newYLimit)
{
break;
@@ -3779,3 +3527,34 @@ void TextBuffer::ManuallyMarkRowAsPrompt(til::CoordType y)
attr.SetMarkAttributes(MarkKind::Prompt);
}
}
// This is an optimization used by the renderer to avoid scheduling a timer if not necessary;
// unlike the renderer, we know the committed range of our own buffer.
bool TextBuffer::ContainsBlinkAttributeInRegion(const Microsoft::Console::Types::Viewport& region) const
{
const auto top = region.Top();
auto bottom = std::min(region.BottomInclusive(), _estimateOffsetOfLastCommittedRow());
for (auto row = top; row < bottom; ++row)
{
const auto& r = GetRowByOffset(row);
for (const auto& attr : r.Attributes())
{
if (attr.IsBlinking())
{
return true;
}
}
}
return false;
}
bool TextBuffer::IsGlyphDoubleWidthAt(const til::point at) const
{
if (!_isRowCommitted(at.y)) [[unlikely]]
{
return false;
}
return _getRow(at.y).DbcsAttrAt(at.x) != DbcsAttribute::Single;
}

View File

@@ -172,15 +172,10 @@ public:
void TriggerNewTextNotification(const std::wstring_view newText);
void TriggerSelection();
til::point GetWordStart(const til::point target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
til::point GetWordEnd(const til::point target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
til::point GetWordStart2(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional = std::nullopt) const;
til::point GetWordEnd2(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional = std::nullopt) const;
til::point GetWordStart(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional = std::nullopt) const;
til::point GetWordEnd(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional = std::nullopt) const;
bool IsWordBoundary(const til::point pos, const std::wstring_view wordDelimiters) const;
bool MoveToNextWord(til::point& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToPreviousWord(til::point& pos, const std::wstring_view wordDelimiters) const;
til::point GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional = std::nullopt) const;
til::point GetGlyphEnd(const til::point pos, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
@@ -315,6 +310,9 @@ public:
void SetScrollbarData(ScrollbarData mark, til::CoordType y);
void ManuallyMarkRowAsPrompt(til::CoordType y);
bool ContainsBlinkAttributeInRegion(const Microsoft::Console::Types::Viewport& region) const;
bool IsGlyphDoubleWidthAt(const til::point at) const;
private:
void _reserve(til::size screenBufferSize, const TextAttribute& defaultAttributes);
void _commit(const std::byte* row);
@@ -324,16 +322,13 @@ private:
ROW& _getRowByOffsetDirect(size_t offset);
ROW& _getRow(til::CoordType y) const;
til::CoordType _estimateOffsetOfLastCommittedRow() const noexcept;
bool _isRowCommitted(til::CoordType y) const noexcept;
void _SetFirstRowIndex(const til::CoordType FirstRowIndex) noexcept;
void _ExpandTextRow(til::inclusive_rect& selectionRow) const;
DelimiterClass _GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const;
til::point _GetDelimiterClassRunStart(til::point pos, const std::wstring_view wordDelimiters) const;
til::point _GetDelimiterClassRunEnd(til::point pos, const std::wstring_view wordDelimiters) const;
til::point _GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const;
til::point _GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
til::point _GetWordEndForAccessibility(const til::point target, const std::wstring_view wordDelimiters, const til::point limit) const;
til::point _GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
til::point _GetDelimiterClassRunStart(til::point pos, const std::wstring_view wordDelimiters, const bool accessibilityMode = false) const;
til::point _GetDelimiterClassRunEnd(til::point pos, const std::wstring_view wordDelimiters, const bool accessibilityMode = false) const;
void _PruneHyperlinks();
std::wstring _commandForRow(const til::CoordType rowOffset, const til::CoordType bottomInclusive, const bool clipAtCursor = false) const;

View File

@@ -34,6 +34,16 @@ class UTextAdapterTests
{
TEST_CLASS(UTextAdapterTests);
TEST_CLASS_SETUP(ClassSetup)
{
wil::unique_hmodule icu{ LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) };
if (!icu)
{
WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped, L"ICU is not present");
}
return true;
}
TEST_METHOD(Unicode)
{
DummyRenderer renderer;

View File

@@ -26,6 +26,9 @@ TARGETLIBS = \
$(CONSOLE_OBJ_PATH)\types\lib\$(O)\ConTypes.lib \
$(TARGETLIBS) \
DELAYLOAD = \
icu.dll \
# -------------------------------------
# Localization
# -------------------------------------

View File

@@ -103,7 +103,7 @@
<!-- Blank the SourceProject here to vend all files into the root of the package. -->
<SourceProject>
</SourceProject>
<!-- Replace the filename for wt/wtd.exe with the one the manifest wants. -->
<!-- Replace the filename for wt/wtd.exe with the one that the manifest wants. -->
<TargetPath Condition="'%(Filename)' == 'wt' and '%(Extension)' == '.exe'">$(OCExecutionAliasName).exe</TargetPath>
</_FilteredNonWapProjProjectOutput>
</ItemGroup>

View File

@@ -237,6 +237,7 @@
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
<rescap:Capability Name="appLicensing" />
</Capabilities>
<Extensions>

View File

@@ -237,6 +237,7 @@
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
<rescap:Capability Name="appLicensing" />
</Capabilities>
<Extensions>

View File

@@ -741,7 +741,7 @@ namespace TerminalAppLocalTests
void SettingsTests::TestNestedInIterableCommand()
{
// This test checks a iterable command that includes a nested command.
// This test checks an iterable command that includes a nested command.
// The commands should look like:
//
// <Command Palette>

View File

@@ -308,6 +308,11 @@ namespace TerminalAppLocalTests
// TerminalPage and not only create them successfully, but also create a
// tab using those settings successfully.
// - - - IMPORTANT - - -
// GH#14623: "closeOnExit": "never" is important for all test profiles. Without
// it, the spawned process exits immediately in the UAP test environment,
// and the default "automatic" close-on-exit behavior removes the
// tab/pane asynchronously, racing against test assertions.
static constexpr std::wstring_view settingsJson0{ LR"(
{
"defaultProfile": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
@@ -315,12 +320,14 @@ namespace TerminalAppLocalTests
{
"name" : "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 1
"historySize": 1,
"closeOnExit": "never"
},
{
"name" : "profile1",
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"historySize": 2
"historySize": 2,
"closeOnExit": "never"
}
]
})" };
@@ -347,10 +354,6 @@ namespace TerminalAppLocalTests
void TabTests::TryDuplicateBadTab()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
// * Create a tab with a profile with GUID 1
// * Reload the settings so that GUID 1 is no longer in the list of profiles
// * Try calling _DuplicateFocusedTab on tab 1
@@ -365,12 +368,14 @@ namespace TerminalAppLocalTests
{
"name" : "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 1
"historySize": 1,
"closeOnExit": "never"
},
{
"name" : "profile1",
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"historySize": 2
"historySize": 2,
"closeOnExit": "never"
}
]
})" };
@@ -382,7 +387,8 @@ namespace TerminalAppLocalTests
{
"name" : "profile1",
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"historySize": 2
"historySize": 2,
"closeOnExit": "never"
}
]
})" };
@@ -438,10 +444,6 @@ namespace TerminalAppLocalTests
void TabTests::TryDuplicateBadPane()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
// * Create a tab with a profile with GUID 1
// * Reload the settings so that GUID 1 is no longer in the list of profiles
// * Try calling _SplitPane(Duplicate) on tab 1
@@ -456,12 +458,14 @@ namespace TerminalAppLocalTests
{
"name" : "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"historySize": 1
"historySize": 1,
"closeOnExit": "never"
},
{
"name" : "profile1",
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"historySize": 2
"historySize": 2,
"closeOnExit": "never"
}
]
})" };
@@ -473,7 +477,8 @@ namespace TerminalAppLocalTests
{
"name" : "profile1",
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"historySize": 2
"historySize": 2,
"closeOnExit": "never"
}
]
})" };
@@ -572,25 +577,29 @@ namespace TerminalAppLocalTests
"name" : "profile0",
"guid": "{6239a42c-1111-49a3-80bd-e8fdd045185c}",
"tabTitle" : "Profile 0",
"historySize": 1
"historySize": 1,
"closeOnExit": "never"
},
{
"name" : "profile1",
"guid": "{6239a42c-2222-49a3-80bd-e8fdd045185c}",
"tabTitle" : "Profile 1",
"historySize": 2
"historySize": 2,
"closeOnExit": "never"
},
{
"name" : "profile2",
"guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"tabTitle" : "Profile 2",
"historySize": 3
"historySize": 3,
"closeOnExit": "never"
},
{
"name" : "profile3",
"guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}",
"tabTitle" : "Profile 3",
"historySize": 4
"historySize": 4,
"closeOnExit": "never"
}
],
"schemes":
@@ -693,7 +702,6 @@ namespace TerminalAppLocalTests
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
auto page = _commonSetup();
@@ -733,10 +741,6 @@ namespace TerminalAppLocalTests
void TabTests::MoveFocusFromZoomedPane()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
auto page = _commonSetup();
Log::Comment(L"Create a second pane");
@@ -782,10 +786,6 @@ namespace TerminalAppLocalTests
void TabTests::CloseZoomedPane()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
auto page = _commonSetup();
Log::Comment(L"Create a second pane");
@@ -841,10 +841,6 @@ namespace TerminalAppLocalTests
void TabTests::SwapPanes()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
auto page = _commonSetup();
Log::Comment(L"Setup 4 panes.");
@@ -1051,31 +1047,31 @@ namespace TerminalAppLocalTests
void TabTests::NextMRUTab()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
// This is a test for GH#8025 - we want to make sure that we can do both
// in-order and MRU tab traversal, using the tab switcher and with the
// tab switcher disabled.
// This is a test for GH#8025 - we want to make sure that MRU tab
// ordering works correctly and that in-order/disabled switching works.
//
// Note: We test MRU ordering directly rather than going through the
// command palette tab switcher, because the palette's anchor key
// handling auto-dismisses when no modifier keys are held (which we
// can't simulate in the test environment).
auto page = _commonSetup();
Log::Comment(L"Create a second tab");
Log::Comment(L"Create Tab[1]");
TestOnUIThread([&page]() {
NewTerminalArgs newTerminalArgs{ 1 };
page->_OpenNewTab(newTerminalArgs);
});
VERIFY_ARE_EQUAL(2u, page->_tabs.Size());
Log::Comment(L"Create a third tab");
Log::Comment(L"Create Tab[2]");
TestOnUIThread([&page]() {
NewTerminalArgs newTerminalArgs{ 2 };
page->_OpenNewTab(newTerminalArgs);
});
VERIFY_ARE_EQUAL(3u, page->_tabs.Size());
Log::Comment(L"Create a fourth tab");
Log::Comment(L"Create Tab[3]");
TestOnUIThread([&page]() {
NewTerminalArgs newTerminalArgs{ 3 };
page->_OpenNewTab(newTerminalArgs);
@@ -1084,99 +1080,89 @@ namespace TerminalAppLocalTests
TestOnUIThread([&page]() {
auto focusedIndex = page->_GetFocusedTabIndex().value_or(-1);
VERIFY_ARE_EQUAL(3u, focusedIndex, L"Verify the fourth tab is the focused one");
VERIFY_ARE_EQUAL(3u, focusedIndex, L"Verify Tab[3] is focused");
});
Log::Comment(L"Select the second tab");
Log::Comment(L"Select Tab[1]");
TestOnUIThread([&page]() {
page->_SelectTab(1);
});
TestOnUIThread([&page]() {
auto focusedIndex = page->_GetFocusedTabIndex().value_or(-1);
VERIFY_ARE_EQUAL(1u, focusedIndex, L"Verify the second tab is the focused one");
VERIFY_ARE_EQUAL(1u, focusedIndex, L"Verify Tab[1] is focused");
});
Log::Comment(L"Change the tab switch order to MRU switching");
// MRU order should now be: Tab[1], Tab[3], Tab[2], Tab[0]
// Verify the MRU list directly.
Log::Comment(L"Verify MRU order: MRU[0]=Tab[1], MRU[1]=Tab[3]");
TestOnUIThread([&page]() {
page->_settings.GlobalSettings().TabSwitcherMode(TabSwitcherMode::MostRecentlyUsed);
VERIFY_ARE_EQUAL(4u, page->_mruTabs.Size());
uint32_t mruIdx;
page->_tabs.IndexOf(page->_mruTabs.GetAt(0), mruIdx);
VERIFY_ARE_EQUAL(1u, mruIdx, L"MRU[0] should be Tab[1] (most recent)");
page->_tabs.IndexOf(page->_mruTabs.GetAt(1), mruIdx);
VERIFY_ARE_EQUAL(3u, mruIdx, L"MRU[1] should be Tab[3] (last tab added)");
});
Log::Comment(L"Switch to the next MRU tab, which is the fourth tab");
Log::Comment(L"Select MRU[1]=Tab[3] directly");
TestOnUIThread([&page]() {
page->_SelectNextTab(true, nullptr);
});
Log::Comment(L"Sleep to let events propagate");
Sleep(250);
TestOnUIThread([&page]() {
Log::Comment(L"Hide the command palette, to confirm the selection");
// If you don't do this, the palette will just stay open, and the
// next time we call _HandleNextTab, we'll continue traversing the
// MRU list, instead of just hoping one entry.
page->LoadCommandPalette().Visibility(Visibility::Collapsed);
// The next MRU tab after Tab[1] is Tab[3]
uint32_t nextMruIdx;
page->_tabs.IndexOf(page->_mruTabs.GetAt(1), nextMruIdx);
page->_SelectTab(nextMruIdx);
});
TestOnUIThread([&page]() {
auto focusedIndex = page->_GetFocusedTabIndex().value_or(-1);
VERIFY_ARE_EQUAL(3u, focusedIndex, L"Verify the fourth tab is the focused one");
VERIFY_ARE_EQUAL(3u, focusedIndex, L"Verify Tab[3] is focused");
});
Log::Comment(L"Switch to the next MRU tab, which is the second tab");
Log::Comment(L"Select MRU[1]=Tab[1] directly");
TestOnUIThread([&page]() {
page->_SelectNextTab(true, nullptr);
});
Log::Comment(L"Sleep to let events propagate");
Sleep(250);
TestOnUIThread([&page]() {
Log::Comment(L"Hide the command palette, to confirm the selection");
// If you don't do this, the palette will just stay open, and the
// next time we call _HandleNextTab, we'll continue traversing the
// MRU list, instead of just hoping one entry.
page->LoadCommandPalette().Visibility(Visibility::Collapsed);
uint32_t nextMruIdx;
page->_tabs.IndexOf(page->_mruTabs.GetAt(1), nextMruIdx);
page->_SelectTab(nextMruIdx);
});
TestOnUIThread([&page]() {
auto focusedIndex = page->_GetFocusedTabIndex().value_or(-1);
VERIFY_ARE_EQUAL(1u, focusedIndex, L"Verify the second tab is the focused one");
});
Log::Comment(L"Change the tab switch order to in-order switching");
page->_settings.GlobalSettings().TabSwitcherMode(TabSwitcherMode::InOrder);
Log::Comment(L"Switch to the next in-order tab, which is the third tab");
TestOnUIThread([&page]() {
page->_SelectNextTab(true, nullptr);
});
TestOnUIThread([&page]() {
auto focusedIndex = page->_GetFocusedTabIndex().value_or(-1);
VERIFY_ARE_EQUAL(2u, focusedIndex, L"Verify the third tab is the focused one");
VERIFY_ARE_EQUAL(1u, focusedIndex, L"Verify Tab[1] is focused");
});
// The Disabled tab switcher mode uses direct index-based switching
// without the command palette, so it works in the test environment.
Log::Comment(L"Change the tab switch order to not use the tab switcher (which is in-order always)");
page->_settings.GlobalSettings().TabSwitcherMode(TabSwitcherMode::Disabled);
Log::Comment(L"Switch to the next in-order tab, which is the fourth tab");
Log::Comment(L"Switch to the next in-order tab: Tab[2]");
TestOnUIThread([&page]() {
page->_SelectNextTab(true, nullptr);
});
TestOnUIThread([&page]() {
auto focusedIndex = page->_GetFocusedTabIndex().value_or(-1);
VERIFY_ARE_EQUAL(3u, focusedIndex, L"Verify the fourth tab is the focused one");
VERIFY_ARE_EQUAL(2u, focusedIndex, L"Verify Tab[2] is focused");
});
Log::Comment(L"Switch to the next in-order tab: Tab[3]");
TestOnUIThread([&page]() {
page->_SelectNextTab(true, nullptr);
});
TestOnUIThread([&page]() {
auto focusedIndex = page->_GetFocusedTabIndex().value_or(-1);
VERIFY_ARE_EQUAL(3u, focusedIndex, L"Verify Tab[3] is focused");
});
}
void TabTests::VerifyCommandPaletteTabSwitcherOrder()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
// This is a test for GH#8188 - we want to make sure that the order of tabs
// is preserved in the CommandPalette's TabSwitcher
// This is a test for GH#8188 - we want to make sure that the MRU
// ordering is correctly maintained as tabs are selected.
//
// Note: We verify MRU ordering directly rather than going through
// the command palette tab switcher, because the palette's anchor key
// handling auto-dismisses when no modifier keys are held (which we
// can't simulate in the test environment).
auto page = _commonSetup();
@@ -1189,7 +1175,7 @@ namespace TerminalAppLocalTests
});
VERIFY_ARE_EQUAL(4u, page->_mruTabs.Size());
Log::Comment(L"give alphabetical names to all switch tab actions");
Log::Comment(L"give alphabetical names to all tabs");
TestOnUIThread([&page]() {
page->_GetTabImpl(page->_tabs.GetAt(0))->Title(L"a");
});
@@ -1211,18 +1197,14 @@ namespace TerminalAppLocalTests
VERIFY_ARE_EQUAL(L"c", page->_tabs.GetAt(2).Title());
VERIFY_ARE_EQUAL(L"d", page->_tabs.GetAt(3).Title());
// MRU order after creating Tab[0]-Tab[3]: MRU[0]=Tab[3], MRU[3]=Tab[0]
VERIFY_ARE_EQUAL(L"d", page->_mruTabs.GetAt(0).Title());
VERIFY_ARE_EQUAL(L"c", page->_mruTabs.GetAt(1).Title());
VERIFY_ARE_EQUAL(L"b", page->_mruTabs.GetAt(2).Title());
VERIFY_ARE_EQUAL(L"a", page->_mruTabs.GetAt(3).Title());
});
Log::Comment(L"Change the tab switch order to MRU switching");
TestOnUIThread([&page]() {
page->_settings.GlobalSettings().TabSwitcherMode(TabSwitcherMode::MostRecentlyUsed);
});
Log::Comment(L"Select the tabs from 0 to 3");
Log::Comment(L"Select Tab[0] through Tab[3] to establish MRU order");
RunOnUIThread([&page]() {
page->_UpdatedSelectedTab(page->_tabs.GetAt(0));
page->_UpdatedSelectedTab(page->_tabs.GetAt(1));
@@ -1230,47 +1212,31 @@ namespace TerminalAppLocalTests
page->_UpdatedSelectedTab(page->_tabs.GetAt(3));
});
Log::Comment(L"Verify MRU order: MRU[0]='d', MRU[1]='c', MRU[2]='b', MRU[3]='a'");
VERIFY_ARE_EQUAL(4u, page->_mruTabs.Size());
VERIFY_ARE_EQUAL(L"d", page->_mruTabs.GetAt(0).Title());
VERIFY_ARE_EQUAL(L"c", page->_mruTabs.GetAt(1).Title());
VERIFY_ARE_EQUAL(L"b", page->_mruTabs.GetAt(2).Title());
VERIFY_ARE_EQUAL(L"a", page->_mruTabs.GetAt(3).Title());
Log::Comment(L"Switch to the next MRU tab, which is the third tab");
RunOnUIThread([&page]() {
page->_SelectNextTab(true, nullptr);
// In the course of a single tick, the Command Palette will:
// * open
// * select the proper tab from the mru's list
// * raise an event for _filteredActionsView().SelectionChanged to
// immediately preview the new tab
// * raise a _SwitchToTabRequestedHandlers event
// * then dismiss itself, because we can't fake holing down an
// anchor key in the tests
Log::Comment(L"Select Tab[2]='c' (MRU[1] after 'd')");
TestOnUIThread([&page]() {
page->_SelectTab(2);
});
Log::Comment(L"Verify MRU order updated: MRU[0]='c', MRU[1]='d', MRU[2]='b', MRU[3]='a'");
TestOnUIThread([&page]() {
VERIFY_ARE_EQUAL(L"c", page->_mruTabs.GetAt(0).Title());
VERIFY_ARE_EQUAL(L"d", page->_mruTabs.GetAt(1).Title());
VERIFY_ARE_EQUAL(L"b", page->_mruTabs.GetAt(2).Title());
VERIFY_ARE_EQUAL(L"a", page->_mruTabs.GetAt(3).Title());
});
const auto palette = winrt::get_self<winrt::TerminalApp::implementation::CommandPalette>(page->LoadCommandPalette());
VERIFY_ARE_EQUAL(winrt::TerminalApp::implementation::CommandPaletteMode::TabSwitchMode, palette->_currentMode, L"Verify we are in the tab switcher mode");
// At this point, the contents of the command palette's _mruTabs list is
// still the _old_ ordering (d, c, b, a). The ordering is only updated
// in TerminalPage::_SelectNextTab, but as we saw before, the palette
// will also dismiss itself immediately when that's called. So we can't
// really inspect the contents of the list in this test, unfortunately.
}
void TabTests::TestWindowRenameSuccessful()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
auto page = _commonSetup();
@@ -1303,7 +1269,6 @@ namespace TerminalAppLocalTests
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
auto page = _commonSetup();
@@ -1336,10 +1301,6 @@ namespace TerminalAppLocalTests
void TabTests::TestPreviewCommitScheme()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
Log::Comment(L"Preview a color scheme. Make sure it's applied, then committed accordingly");
auto page = _commonSetup();
@@ -1402,10 +1363,6 @@ namespace TerminalAppLocalTests
void TabTests::TestPreviewDismissScheme()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
Log::Comment(L"Preview a color scheme. Make sure it's applied, then dismissed accordingly");
auto page = _commonSetup();
@@ -1454,10 +1411,6 @@ namespace TerminalAppLocalTests
void TabTests::TestPreviewSchemeWhilePreviewing()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
Log::Comment(L"Preview a color scheme, then preview another scheme. ");
Log::Comment(L"Preview a color scheme. Make sure it's applied, then committed accordingly");
@@ -1525,10 +1478,6 @@ namespace TerminalAppLocalTests
void TabTests::TestClampSwitchToTab()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Ignore", L"True") // GH#19610 tracks re-enabling this test
END_TEST_METHOD_PROPERTIES()
Log::Comment(L"Test that switching to a tab index higher than the number of tabs just clamps to the last tab.");
auto page = _commonSetup();

View File

@@ -192,7 +192,7 @@
ResourceKey="TabViewBackground" />
<SolidColorBrush x:Key="SettingsUiTabBrush"
Color="#0c0c0c" />
Color="#282828" />
<SolidColorBrush x:Key="BroadcastPaneBorderColor"
Color="{StaticResource SystemAccentColorDark2}" />
@@ -211,7 +211,7 @@
ResourceKey="TabViewBackground" />
<SolidColorBrush x:Key="SettingsUiTabBrush"
Color="#ffffff" />
Color="#F9F9F9" />
<SolidColorBrush x:Key="BroadcastPaneBorderColor"
Color="{StaticResource SystemAccentColorLight2}" />
@@ -234,7 +234,7 @@
ResourceKey="SystemColorButtonFaceColorBrush" />
<StaticResource x:Key="SettingsUiTabBrush"
ResourceKey="SystemControlBackgroundBaseLowBrush" />
ResourceKey="SystemColorWindowBrush" />
<SolidColorBrush x:Key="BroadcastPaneBorderColor"
Color="{StaticResource SystemColorHighlightColor}" />

View File

@@ -499,8 +499,8 @@ namespace winrt::TerminalApp::implementation
}
else
{
_ResizePane(realArgs.ResizeDirection());
args.Handled(true);
const auto resizeSucceeded = _ResizePane(realArgs.ResizeDirection());
args.Handled(resizeSucceeded);
}
}
}
@@ -801,7 +801,7 @@ namespace winrt::TerminalApp::implementation
_RemoveTabs(tabsToRemove);
actionArgs.Handled(true);
actionArgs.Handled(!tabsToRemove.empty());
}
}
@@ -837,7 +837,7 @@ namespace winrt::TerminalApp::implementation
// tab row, until you mouse over them. Probably has something to do
// with tabs not resizing down until there's a mouse exit event.
actionArgs.Handled(true);
actionArgs.Handled(!tabsToRemove.empty());
}
}
@@ -1475,7 +1475,7 @@ namespace winrt::TerminalApp::implementation
WI_IsAnyFlagSet(source, SuggestionsSource::CommandHistory | SuggestionsSource::QuickFixes);
if (const auto& control{ _GetActiveControl() })
{
currentWorkingDirectory = control.CurrentWorkingDirectory();
currentWorkingDirectory = control.WorkingDirectory();
if (shouldGetContext)
{

View File

@@ -1068,6 +1068,15 @@ int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring> args)
return 0;
}
// When a toast notification is clicked, Windows may launch a new instance
// with "--from-toast" as the argument. This is a no-op sentinel — the
// in-process Activated handler on the toast already handled activation.
// See DesktopNotification.cpp for more details.
if (args.size() == 2 && args[1] == L"--from-toast")
{
return 0;
}
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
for (auto& cmdBlob : commands)

View File

@@ -294,7 +294,7 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Registers for changes to the settings folder and upon a updated settings
// - Registers for changes to the settings folder and upon an updated settings
// profile calls ReloadSettings().
// Arguments:
// - <none>
@@ -307,7 +307,7 @@ namespace winrt::TerminalApp::implementation
settingsPath.parent_path().c_str(),
false,
// We want file modifications, AND when files are renamed to be
// settings.json. This second case will oftentimes happen with text
// settings.json. This second case will often happen with text
// editors, who will write a temp file, then rename it to be the
// actual file you wrote. So listen for that too.
wil::FolderChangeEvents::FileName | wil::FolderChangeEvents::LastWriteTime,

View File

@@ -15,6 +15,7 @@ namespace winrt::TerminalApp::implementation
til::typed_event<IPaneContent> TaskbarProgressChanged;
til::typed_event<IPaneContent> ReadOnlyChanged;
til::typed_event<IPaneContent> FocusRequested;
til::typed_event<IPaneContent, winrt::TerminalApp::NotificationEventArgs> NotificationRequested;
til::typed_event<winrt::Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command> DispatchCommandRequested;
};

View File

@@ -741,10 +741,10 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Helper method for retrieving the action from a command the user
// selected, and dispatching that command. Also fires a tracelogging event
// indicating that the user successfully found the action they were
// looking for.
// - Helper method to run a command, switch to a tab, or retrieve the
// action from a user selected command and dispatch that command.
// Also fires a tracelogging event indicating that the user successfully
// found the action they were looking for.
// Arguments:
// - command: the Command to dispatch. This might be null.
// Return Value:
@@ -791,7 +791,7 @@ namespace winrt::TerminalApp::implementation
_close();
// But make an exception for the Toggle Command Palette action: we don't want the dispatch
// make the command palette - that was just closed - visible again.
// to make the command palette - that was just closed - visible again.
// All other actions can just be dispatched.
if (command.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{

View File

@@ -0,0 +1,129 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "DesktopNotification.h"
#include <WtExeUtils.h>
using namespace winrt::Windows::UI::Notifications;
using namespace winrt::Windows::Data::Xml::Dom;
namespace winrt::TerminalApp::implementation
{
std::atomic<uint64_t> DesktopNotification::_lastNotificationTime{ 0 };
// Method Description:
// - Rate-limits toast notifications so we don't spam the user.
// Return Value:
// - Returns true if a notification is allowed, false if too recent.
bool DesktopNotification::ShouldSendNotification()
{
const auto now = GetTickCount64();
auto last = _lastNotificationTime.load(std::memory_order_relaxed);
// Subtraction wraps cleanly modulo 2^64, so the delta is correct even
// across the (~584 million year) GetTickCount64 rollover.
if (now - last < MinNotificationIntervalMs)
{
return false;
}
// Attempt to update; if another thread beat us, that's fine — we'll skip this one.
return _lastNotificationTime.compare_exchange_strong(last, now, std::memory_order_relaxed);
}
// Method Description:
// - Sends a toast notification with the given title and message.
// - When the user clicks the toast, the `Activated` callback fires
// with the tabIndex that was passed in, so the caller can switch
// to the correct tab and summon the window.
// Arguments:
// - args: The title, message, and tab index to include in the notification.
// - activated: A callback invoked on the background thread when the
// toast is clicked. The uint32_t parameter is the tab index.
void DesktopNotification::SendNotification(const DesktopNotificationArgs& args, std::function<void()> activatedFunc)
{
try
{
if (!ShouldSendNotification())
{
return;
}
// Build the toast XML. We use a simple template with a title and body text.
//
// <toast launch="--from-toast">
// <visual>
// <binding template="ToastGeneric">
// <text>Title</text>
// <text>Message</text>
// </binding>
// </visual>
// </toast>
auto toastXml = ToastNotificationManager::GetTemplateContent(ToastTemplateType::ToastText02);
auto textNodes = toastXml.GetElementsByTagName(L"text");
// First <text> is the title
textNodes.Item(0).InnerText(args.Title);
// Second <text> is the body
textNodes.Item(1).InnerText(args.Message);
auto toastElement = toastXml.DocumentElement();
// When a toast is clicked, Windows launches a new instance of the app
// with the "launch" attribute as command-line arguments. We handle
// toast activation in-process via the Activated event below, so the
// new instance should do nothing. "--from-toast" is recognized by
// AppCommandlineArgs::ParseArgs as a no-op sentinel.
toastElement.SetAttribute(L"launch", L"--from-toast");
toastElement.SetAttribute(L"scenario", L"default");
auto toast = ToastNotification{ toastXml };
// Set the tag and group to enable notification replacement.
// Repeated notifications with the same tag replace the previous one
// rather than stacking in the notification center.
toast.Tag(args.Tag);
toast.Group(L"WindowsTerminal");
// When the user activates (clicks) the toast, fire the callback.
if (activatedFunc)
{
toast.Activated([activatedFunc](const auto& /*sender*/, const auto& /*eventArgs*/) {
activatedFunc();
});
}
// For packaged apps, CreateToastNotifier() uses the package identity automatically.
// For unpackaged apps, we must pass the explicit AUMID that was registered
// at startup via SetCurrentProcessExplicitAppUserModelID.
winrt::Windows::UI::Notifications::ToastNotifier notifier{ nullptr };
if (IsPackaged())
{
notifier = ToastNotificationManager::CreateToastNotifier();
}
else
{
// Retrieve the AUMID that was set by WindowEmperor at startup.
wil::unique_cotaskmem_string aumid;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&aumid)))
{
notifier = ToastNotificationManager::CreateToastNotifier(aumid.get());
}
}
if (notifier)
{
notifier.Show(toast);
}
}
catch (...)
{
// Toast notification is a best-effort feature. If it fails (e.g., notifications
// are disabled, or the app is unpackaged without proper AUMID setup), we silently
// ignore the error.
LOG_CAUGHT_EXCEPTION();
}
}
}

View File

@@ -0,0 +1,37 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- DesktopNotification.h
Module Description:
- Helper for sending Windows desktop toast notifications. Used to surface
terminal activity events to the user via the Windows notification center.
--*/
#pragma once
#include "pch.h"
namespace winrt::TerminalApp::implementation
{
struct DesktopNotificationArgs
{
winrt::hstring Title;
winrt::hstring Message;
winrt::hstring Tag;
};
class DesktopNotification
{
public:
static bool ShouldSendNotification();
static void SendNotification(const DesktopNotificationArgs& args, std::function<void()> activatedFunc);
private:
static std::atomic<uint64_t> _lastNotificationTime;
// Minimum interval between notifications, in milliseconds (GetTickCount64 units).
static constexpr uint64_t MinNotificationIntervalMs = 5'000;
};
}

View File

@@ -14,6 +14,13 @@ namespace TerminalApp
runtimeclass BellEventArgs
{
Boolean FlashTaskbar { get; };
Boolean SendNotification { get; };
};
runtimeclass NotificationEventArgs
{
String Title { get; };
String Body { get; };
};
interface IPaneContent
@@ -46,6 +53,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> TaskbarProgressChanged;
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> ReadOnlyChanged;
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> FocusRequested;
event Windows.Foundation.TypedEventHandler<IPaneContent, NotificationEventArgs> NotificationRequested;
};

View File

@@ -136,7 +136,7 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t n
ActionAndArgs actionAndArgs;
actionAndArgs.Action(ShortcutAction::SplitPane);
const auto terminalArgs{ newPane->GetTerminalArgsForPane(kind) };
// When creating a pane the split size is the size of the new pane
// When creating a pane, the split size is the size of the new pane
// and not position.
const auto splitDirection = _splitState == SplitState::Horizontal ? SplitDirection::Down : SplitDirection::Right;
const auto splitSize = (kind != BuildStartupKind::None && _IsLeaf() ? 0.5f : 1.0f - _desiredSplitPosition);
@@ -2264,7 +2264,7 @@ SplitState Pane::_convertAutomaticOrDirectionalSplitState(const SplitDirection&
// creates a new Pane to host the control, registers event handlers.
// Arguments:
// - splitType: what type of split we should create.
// - splitSize: what fraction of the pane the new pane should get
// - splitSize: the fraction of the pane that the new pane should get
// - newPane: the pane to add as a child
// Return Value:
// - The two newly created Panes, with the original pane as the first pane.

View File

@@ -499,24 +499,48 @@
<value>Hinweise von Drittanbietern</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Abbrechen</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>Alle schließen</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Möchten Sie alle Fenster schließen?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Abbrechen</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Alle schließen</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Möchten Sie alle Registerkarten schließen?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Alle schließen</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Möchten Sie diese Registerkarte schließen?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Registerkarte schließen</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Möchten Sie diesen Bereich schließen?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Bereich schließen</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Möchten Sie diese Registerkarten schließen?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Registerkarten schließen</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Möchten Sie diese Bereiche schließen?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>Bereiche schließen</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Nicht mehr fragen</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Abbrechen</value>
</data>
@@ -672,9 +696,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Dieser Linktyp wird derzeit nicht unterstützt:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Abbrechen</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Dieser Link kann zu einem unsicheren Speicherort führen. Links können ihren Computer und Ihre Daten beschädigen. Klicken Sie zum Schutz Des Computers nur auf Links aus vertrauenswürdigen Quellen.</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Trotzdem öffnen</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Einstellungen</value>
</data>
@@ -742,6 +772,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Aktivität auf der Registerkarte „{0}“</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Aktivität auf der Registerkarte „{0}“ (Fenster „{1}“)</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Eine neue Registerkarte im angegebenen Startverzeichnis öffnen</value>
</data>
@@ -848,11 +886,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>Der aktive Bereich wurde auf die Registerkarte „{0}“ verschoben</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>Registerkarte „{0}“ wurde in das Fenster „{1}“ verschoben</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Registerkarte „{0}“ in neues Fenster verschoben</value>
@@ -864,7 +902,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Der aktive Bereich wurde in das Fenster "{0}" verschoben</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Aktiver Bereich in neues Fenster verschoben</value>
@@ -878,10 +916,10 @@
<value>Wenn diese Option festgelegt ist, wird der Befehl an den Standardbefehl des Profils angefügt, anstatt ihn zu ersetzen.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Verbindung neu starten</value>
<value>Sitzung neu starten</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Verbindung mit aktivem Bereich neu starten</value>
<value>Sitzung im aktiven Bereich neu starten</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Schnipsel</value>

View File

@@ -496,24 +496,48 @@
<value>Third-Party notices</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>Close all</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Do you want to close all windows?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Close all</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Do you want to close all tabs?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Close all</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Do you want to close this tab?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Close tab</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Do you want to close this pane?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Close pane</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Do you want to close these tabs?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Close tabs</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Do you want to close these panes?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>Close panes</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Don't ask me again</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Cancel</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>This link type is currently not supported:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>This link may lead to an unsafe location. Hyperlinks can be harmful to your computer and data. To protect your computer, only click links from trusted sources.</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Open anyway</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Settings</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Activity in tab "{0}"</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Activity in tab "{0}" (window "{1}")</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Open a new tab in given starting directory</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>Active pane moved to "{0}" tab</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>"{0}" tab moved to "{1}" window</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>"{0}" tab moved to new window</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Active pane moved to "{0}" window</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Active pane moved to new window</value>
@@ -875,10 +913,10 @@
<value>If set, the command will be appended to the profile's default command instead of replacing it.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Restart connection</value>
<value>Restart session</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Restart the active pane connection</value>
<value>Restart the session in the active pane</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Snippets</value>

View File

@@ -496,24 +496,48 @@
<value>Avisos de terceros</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>Cerrar todo</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>¿Quiere cerrar todas las ventanas?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Cerrar todo</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>¿Quieres cerrar todas las pestañas?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Cerrar todo</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>¿Desea cerrar esta pestaña?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Cerrar pestaña</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>¿Desea cerrar este panel?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Cerrar panel</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>¿Desea cerrar estas pestañas?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Cerrar pestañas</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>¿Desea cerrar estos paneles?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>Cerrar paneles</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>No volver a preguntarme</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Cancelar</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Este tipo de vínculo no se admite actualmente:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Este vínculo puede dar lugar a una ubicación no segura. Los hipervínculos pueden ser perjudiciales para el equipo y los datos. Para proteger el equipo, haga clic solo en vínculos de orígenes de confianza.</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Abrir de todas formas</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Configuración</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Actividad en la pestaña "{0}"</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Actividad en la pestaña "{0}" (ventana "{1}")</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Abrir una nueva pestaña en un directorio de inicio determinado</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>Panel activo movido a la pestaña "{0}"</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>La pestaña "{0}" se ha movido a la ventana "{1}"</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>La pestaña "{0}" se ha movido a la nueva ventana</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Panel activo movido a la ventana "{0}"</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Panel activo movido a nueva ventana</value>
@@ -875,10 +913,10 @@
<value>Si se establece, el comando se anexará al comando predeterminado del perfil en lugar de reemplazarlo.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Reiniciar conexión</value>
<value>Reiniciar sesión</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Reiniciar la conexión del panel activo</value>
<value>Reiniciar la sesión en el panel activo</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Fragmentos</value>

View File

@@ -496,24 +496,48 @@
<value>Mentions tierces</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Annuler</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>Fermer tout</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Voulez-vous fermer toutes les fenêtres ?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Annuler</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Fermer tout</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Voulez-vous fermer tous les onglets ?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Fermer tout</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Voulez-vous fermer cet onglet ?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Fermer l'onglet</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Voulez-vous fermer ce volet ?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Fermer le volet</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Voulez-vous fermer ces onglets ?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Fermer les onglets</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Voulez-vous fermer ces volets ?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>Fermer les panneaux</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Ne plus me le demander</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Annuler</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Ce type de lien nest actuellement pas pris en charge :</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Annuler</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Ce lien peut entraîner un emplacement non sécurisé. Les liens hypertexte peuvent endommager votre ordinateur et vos données. Pour protéger votre ordinateur, cliquez uniquement sur des liens provenant de sources fiables.</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Ouvrir quand même</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Paramètres</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Activité sous longlet « {0} »</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Activité sous longlet « {0} » (fenêtre « {1} »)</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Ouvrez un nouvel onglet dans le répertoire correspondant</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>Volet actif déplacé vers longlet « {0} »</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>Onglet « {0} » déplacé vers la fenêtre « {1} »</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Onglet « {0} » déplacé vers une nouvelle fenêtre</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Volet actif déplacé vers longlet « {0} »</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Volet actif déplacé vers une nouvelle fenêtre</value>
@@ -875,10 +913,10 @@
<value>Si elle est définie, la commande sera ajoutée à la commande par défaut du profil au lieu de la remplacer.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Redémarrer la connexion</value>
<value>Redémarrer la session</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Redémarrer la connexion du volet actif</value>
<value>Redémarrez la session dans le volet actif</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Extraits</value>

View File

@@ -496,24 +496,48 @@
<value>Comunicazioni di terze parti</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Annulla</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>Chiudi tutto</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Vuoi chiudere tutte le finestre?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Annulla</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Chiudi tutto</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Vuoi chiudere tutte le schede?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Chiudi tutto</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Vuoi chiudere questa scheda?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Chiudi scheda</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Vuoi chiudere questo riquadro?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Chiudi riquadro</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Vuoi chiudere queste schede?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Chiudi schede</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Vuoi chiudere questi riquadri?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>Chiudi riquadri</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Non chiedermelo più</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Annulla</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Questo tipo di collegamento non è al momento supportato:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Annulla</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Questo collegamento potrebbe causare un percorso non sicuro. I collegamenti ipertestuali possono essere dannosi per il computer e i dati. Per proteggere il computer, fare clic solo su collegamenti da origini attendibili.</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Apri comunque</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Impostazioni</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Attività nella scheda "{0}"</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Attività nella scheda "{0}" (finestra "{1}")</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Apri una nuova scheda nella directory di avvio specificata</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>Riquadro attivo spostato nella scheda "{0}"</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>Scheda "{0}" spostata nella finestra "{1}"</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Scheda "{0}" spostata in una nuova finestra</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Riquadro attivo spostato nella finestra "{0}"</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Riquadro attivo spostato in una nuova finestra</value>
@@ -875,10 +913,10 @@
<value>Se impostato, il comando verrà aggiunto al comando predefinito del profilo invece di sostituirlo.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Riavvia connessione</value>
<value>Riavvia la sessione</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Riavvia la connessione al riquadro attivo</value>
<value>Riavvia la sessione nel riquadro attivo</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Frammenti</value>

View File

@@ -497,24 +497,48 @@
<value>サード パーティ通知</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>キャンセル</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>すべて閉じる</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>すべてのウィンドウを閉じますか?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>キャンセル</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>すべて閉じる</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>すべてのタブを閉じますか?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>すべて閉じる</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>このタブを閉じますか?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>タブを閉じる</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>このウィンドウを閉じますか?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>ウィンドウを閉じる</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>これらのタブを閉じますか?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>タブを閉じる</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>これらのウィンドウを閉じますか?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>ウィンドウを閉じる</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>今後、このメッセージを表示しない</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>キャンセル</value>
</data>
@@ -670,9 +694,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>このリンクの種類は現在サポートされていません:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>キャンセル</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>このリンクは安全でない可能性があります。ハイパーリンクは、コンピューターやデータに問題を起こす可能性があります。コンピューターを保護するには、信頼できるソースからのリンクのみをクリックしてください。</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>開く</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>設定</value>
</data>
@@ -740,6 +770,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>タブ "{0}" のアクティビティ</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>タブ "{0}" のアクティビティ (ウィンドウ "{1}")</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>指定された開始ディレクトリで新しいタブを開きます</value>
</data>
@@ -846,11 +884,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>アクティブなペインを [{0}] タブに移動しました</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>[{0}] タブを "{1}" ウィンドウに移動しました</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>[{0}] タブを新しいウィンドウに移動しました</value>
@@ -862,7 +900,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>アクティブなペインを "{0}" ウィンドウに移動しました</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>アクティブなペインを新しいウィンドウに移動しました</value>
@@ -876,10 +914,10 @@
<value>設定されている場合、コマンドはプロファイルの既定のコマンドを置き換えるのではなく、追加されます。</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>接続の再起動</value>
<value>セッションの再開</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>アクティブ ペイン接続を再起動します</value>
<value>アクティブなウィンドウでセッションを再起動します</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>抜粋</value>

View File

@@ -496,24 +496,48 @@
<value>타사 통지</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>취소</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>모두 닫기</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>모든 창을 닫으시겠습니까?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>취소</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>모두 닫기</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>모든 탭을 닫으시겠습니까?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>모두 닫기</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>이 탭을 닫으시겠습니까?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>탭 닫기</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>이 창을 닫으시겠습니까?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>창 닫기</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>이러한 탭을 닫으시겠습니까?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>탭 닫기</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>이 창을 닫으시겠습니까?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>창 닫기</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>다시 묻지 않기</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>취소</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>이 링크 형식은 현재 지원되지 않습니다.</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>취소</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>이 링크로 인해 안전하지 않은 위치가 발생할 수 있습니다. 하이퍼링크는 컴퓨터와 데이터를 손상시킬 수 있습니다. 컴퓨터를 보호하려면 신뢰할 수 있는 원본의 링크만 클릭하세요.</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>열기</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>설정</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>"{0}" 탭의 활동</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>"{0}" 탭의 활동(창 "{1}")</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>지정된 시작 디렉터리에서 새 탭 열기</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>활성 창이 "{0}" 탭으로 이동됨</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>"{0}" 탭이 "{1}" 창으로 이동됨</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>"{0}" 탭이 새 창으로 이동됨</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>활성 창이 "{0}" 창으로 이동됨</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>활성 창이 새 창으로 이동됨</value>
@@ -875,10 +913,10 @@
<value>설정하면 이 명령은 프로필의 기본 명령 대신 프로필의 기본 명령에 추가됩니다.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>연결 다시 시작</value>
<value>세션 다시 시작</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>활성 창 연결 다시 시작</value>
<value>활성 창에서 세션을 다시 시작하세요.</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>짧은 요약</value>

View File

@@ -496,24 +496,48 @@
<value>Avisos de Terceiros</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>Fechar tudo</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Deseja fechar todas as janelas?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Fechar tudo</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Deseja fechar todas as guias?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Fechar tudo</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Deseja fechar esta guia?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Fechar guia</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Deseja fechar este painel?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Fechar painel</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Deseja fechar estas guias?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Fechar guias</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Deseja fechar estes painéis?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>Fechar painéis</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Não me pergunte novamente</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Cancelar</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Não há suporte para este tipo de link no momento:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Este link pode levar a um local não seguro. Hiperlinks podem ser prejudiciais ao computador e aos dados. Para proteger o computador, clique somente em links de fontes confiáveis.</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Abrir mesmo assim</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Configurações</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Atividade na aba "{0}"</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Atividade na aba "{0}" (janela "{1}")</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Abrir uma nova guia no diretório inicial fornecido</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>Painel ativo movido para a guia "{0}"</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>Guia "{0}" movida para janela "{1}"</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Guia "{0}" movida para nova janela</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Painel ativo movido para a janela "{0}"</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Painel ativo movido para nova janela</value>
@@ -875,10 +913,10 @@
<value>Se definido, o comando será acrescentado ao comando padrão do perfil em vez de substituí-lo.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Reiniciar conexão</value>
<value>Reiniciar sessão</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Reiniciar a conexão do painel ativo</value>
<value>Reinicie a sessão no painel ativo</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Trechos</value>

View File

@@ -496,23 +496,47 @@
<value>Ţћĩřð-Ρářŧγ ñοŧīĉęŝ !!! !!!</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<value>Ċдйĉέł !</value>
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Ĉάйçэļ !</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>€ļőşε áļľ !!!</value>
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Ďő убυ ẅåήт ţø ¢ľöѕē äľľ ẃιⁿðŏŵş? !!! !!! !!! </value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<value>Ďõ γбű ẁāŋţ ťó ςℓσśĕ äℓℓ шîйđбẁś? !!! !!! !!! </value>
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Ċľóѕε ªĺĺ !!!</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Ćăʼnċęℓ !</value>
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Ďō γőű шдπŧ ŧò ςłοѕз āĺℓ ţäьš? !!! !!! !!!</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<value>Ćļõѕέ аłℓ !!!</value>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Ĉŀõśê āłĺ !!!</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<value>Đσ ŷőū шдиŧ тò čļòŝз αŀľ ţâвŝ? !!! !!! !!!</value>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Đó уøυ ẅāńť тο çŀǿśę ŧĥíš τάъ? !!! !!! !!!</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Ċℓοѕē ţαъ !!!</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Đò γθũ ώăńт ťǿ ¢ℓσŝę ŧħîŝ ρаńе? !!! !!! !!!</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Ĉŀбśз φдŋё !!!</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Đó ўоú ŵąňτ ŧò çŀσѕė ŧћěśé ţдьş? !!! !!! !!! </value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Ćŀöśé ŧãвś !!!</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Ðǿ ỳбū ŵáήť ŧо ćļόśě τнέšê φăñєš? !!! !!! !!! </value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>€łǿśē рāⁿęѕ !!!</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Đòñ'ť ªѕķ мë àĝáîⁿ !!! !!</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Čǻñčėŀ !</value>
@@ -669,8 +693,14 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Ťђïś łϊηќ ŧурē ιş çũґѓзⁿτľÿ ñστ şΰρρоŕŧĕđ: !!! !!! !!! !!! </value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<value>Сąñс℮ł !</value>
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Çдπсёľ !</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Ŧђīś ℓîŋќ мαў ľêãδ τб áń úʼnšàƒé ℓоćάŧίоñ. Ĥўрзŗℓĭŋķѕ çâⁿ ъέ ђąřмƒúļ τό ўôця ċómφύŧèґ аňδ ðáťǻ. Ţб ρгøťėçŧ ўòύг ςömφùţĕŕ, ŏŋľỳ čℓΐςķ łίŋκѕ ƒřöм ťŗμѕŧєđ śόυяčêś. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!!</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Őρέй ǻпŷŵãγ !!!</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Śëţťĩпğś !!</value>
@@ -739,6 +769,14 @@
<value>Ẃϊйδοŵš !!</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Δćţíνïŧý īй τаь "{0}" !!! !!!</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Δсŧìνιŧý įņ ţªь "{0}" (ŵϊņδόώ "{1}") !!! !!! !!! !</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Фφĕń ª пёẅ ţâь ίи ğīνęņ ѕŧāятĩлğ δįŗęćтŏяγ !!! !!! !!! !!! </value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>∆çťíνĕ рåⁿэ мôνеð ťб "{0}" ţав !!! !!! !!!</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>"{0}" ťāъ мōνęđ τŏ "{1}" шΐπδŏẅ !!! !!! !!!</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>"{0}" тąь mǿνєđ ŧσ ήèώ ẅĩŋďøẃ !!! !!! !!!</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Λςťìνє рáиė mόνéð ťб "{0}" ŵîńđθω !!! !!! !!! </value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Αĉťįνέ ρªņз mσνёđ τǿ ήёẃ ẃîпďǿω !!! !!! !!!</value>
@@ -875,10 +913,10 @@
<value>Ĩƒ šęţ, ŧнĕ ¢ömmдлδ ŵîĺł ьέ åφрєйδĕđ τσ ŧђė рřŏƒїłє'ş đзƒªūľţ ¢οmмăńδ іñѕţέáđ øƒ ѓēρļąċĭлĝ їţ. !!! !!! !!! !!! !!! !!! !!! !!! !!! !</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Γēѕŧâяŧ ćǿńńēčťїöл !!! !!</value>
<value>Γēѕŧâяŧ ŝєѕѕïσⁿ !!! !</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Γėşťáгţ ŧħ℮ ãčтĩνέ ρăйё сǿηńëςтιóņ !!! !!! !!! !</value>
<value>Γėşťáгţ ŧħ℮ ŝёšŝīőń įй τђ℮ ăċţΐνе φǻñē !!! !!! !!! !!</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Šņíрρēťş !!</value>

View File

@@ -496,23 +496,47 @@
<value>Ţћĩřð-Ρářŧγ ñοŧīĉęŝ !!! !!!</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<value>Ċдйĉέł !</value>
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Ĉάйçэļ !</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>€ļőşε áļľ !!!</value>
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Ďő убυ ẅåήт ţø ¢ľöѕē äľľ ẃιⁿðŏŵş? !!! !!! !!! </value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<value>Ďõ γбű ẁāŋţ ťó ςℓσśĕ äℓℓ шîйđбẁś? !!! !!! !!! </value>
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Ċľóѕε ªĺĺ !!!</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Ćăʼnċęℓ !</value>
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Ďō γőű шдπŧ ŧò ςłοѕз āĺℓ ţäьš? !!! !!! !!!</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<value>Ćļõѕέ аłℓ !!!</value>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Ĉŀõśê āłĺ !!!</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<value>Đσ ŷőū шдиŧ тò čļòŝз αŀľ ţâвŝ? !!! !!! !!!</value>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Đó уøυ ẅāńť тο çŀǿśę ŧĥíš τάъ? !!! !!! !!!</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Ċℓοѕē ţαъ !!!</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Đò γθũ ώăńт ťǿ ¢ℓσŝę ŧħîŝ ρаńе? !!! !!! !!!</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Ĉŀбśз φдŋё !!!</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Đó ўоú ŵąňτ ŧò çŀσѕė ŧћěśé ţдьş? !!! !!! !!! </value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Ćŀöśé ŧãвś !!!</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Ðǿ ỳбū ŵáήť ŧо ćļόśě τнέšê φăñєš? !!! !!! !!! </value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>€łǿśē рāⁿęѕ !!!</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Đòñ'ť ªѕķ мë àĝáîⁿ !!! !!</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Čǻñčėŀ !</value>
@@ -669,8 +693,14 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Ťђïś łϊηќ ŧурē ιş çũґѓзⁿτľÿ ñστ şΰρρоŕŧĕđ: !!! !!! !!! !!! </value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<value>Сąñс℮ł !</value>
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Çдπсёľ !</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Ŧђīś ℓîŋќ мαў ľêãδ τб áń úʼnšàƒé ℓоćάŧίоñ. Ĥўрзŗℓĭŋķѕ çâⁿ ъέ ђąřмƒúļ τό ўôця ċómφύŧèґ аňδ ðáťǻ. Ţб ρгøťėçŧ ўòύг ςömφùţĕŕ, ŏŋľỳ čℓΐςķ łίŋκѕ ƒřöм ťŗμѕŧєđ śόυяčêś. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!!</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Őρέй ǻпŷŵãγ !!!</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Śëţťĩпğś !!</value>
@@ -739,6 +769,14 @@
<value>Ẃϊйδοŵš !!</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Δćţíνïŧý īй τаь "{0}" !!! !!!</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Δсŧìνιŧý įņ ţªь "{0}" (ŵϊņδόώ "{1}") !!! !!! !!! !</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Фφĕń ª пёẅ ţâь ίи ğīνęņ ѕŧāятĩлğ δįŗęćтŏяγ !!! !!! !!! !!! </value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>∆çťíνĕ рåⁿэ мôνеð ťб "{0}" ţав !!! !!! !!!</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>"{0}" ťāъ мōνęđ τŏ "{1}" шΐπδŏẅ !!! !!! !!!</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>"{0}" тąь mǿνєđ ŧσ ήèώ ẅĩŋďøẃ !!! !!! !!!</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Λςťìνє рáиė mόνéð ťб "{0}" ŵîńđθω !!! !!! !!! </value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Αĉťįνέ ρªņз mσνёđ τǿ ήёẃ ẃîпďǿω !!! !!! !!!</value>
@@ -875,10 +913,10 @@
<value>Ĩƒ šęţ, ŧнĕ ¢ömmдлδ ŵîĺł ьέ åφрєйδĕđ τσ ŧђė рřŏƒїłє'ş đзƒªūľţ ¢οmмăńδ іñѕţέáđ øƒ ѓēρļąċĭлĝ їţ. !!! !!! !!! !!! !!! !!! !!! !!! !!! !</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Γēѕŧâяŧ ćǿńńēčťїöл !!! !!</value>
<value>Γēѕŧâяŧ ŝєѕѕïσⁿ !!! !</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Γėşťáгţ ŧħ℮ ãčтĩνέ ρăйё сǿηńëςтιóņ !!! !!! !!! !</value>
<value>Γėşťáгţ ŧħ℮ ŝёšŝīőń įй τђ℮ ăċţΐνе φǻñē !!! !!! !!! !!</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Šņíрρēťş !!</value>

View File

@@ -496,23 +496,47 @@
<value>Ţћĩřð-Ρářŧγ ñοŧīĉęŝ !!! !!!</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<value>Ċдйĉέł !</value>
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Ĉάйçэļ !</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>€ļőşε áļľ !!!</value>
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Ďő убυ ẅåήт ţø ¢ľöѕē äľľ ẃιⁿðŏŵş? !!! !!! !!! </value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<value>Ďõ γбű ẁāŋţ ťó ςℓσśĕ äℓℓ шîйđбẁś? !!! !!! !!! </value>
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Ċľóѕε ªĺĺ !!!</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Ćăʼnċęℓ !</value>
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Ďō γőű шдπŧ ŧò ςłοѕз āĺℓ ţäьš? !!! !!! !!!</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<value>Ćļõѕέ аłℓ !!!</value>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Ĉŀõśê āłĺ !!!</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<value>Đσ ŷőū шдиŧ тò čļòŝз αŀľ ţâвŝ? !!! !!! !!!</value>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Đó уøυ ẅāńť тο çŀǿśę ŧĥíš τάъ? !!! !!! !!!</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Ċℓοѕē ţαъ !!!</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Đò γθũ ώăńт ťǿ ¢ℓσŝę ŧħîŝ ρаńе? !!! !!! !!!</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Ĉŀбśз φдŋё !!!</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Đó ўоú ŵąňτ ŧò çŀσѕė ŧћěśé ţдьş? !!! !!! !!! </value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Ćŀöśé ŧãвś !!!</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Ðǿ ỳбū ŵáήť ŧо ćļόśě τнέšê φăñєš? !!! !!! !!! </value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>€łǿśē рāⁿęѕ !!!</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Đòñ'ť ªѕķ мë àĝáîⁿ !!! !!</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Čǻñčėŀ !</value>
@@ -669,8 +693,14 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Ťђïś łϊηќ ŧурē ιş çũґѓзⁿτľÿ ñστ şΰρρоŕŧĕđ: !!! !!! !!! !!! </value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<value>Сąñс℮ł !</value>
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Çдπсёľ !</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Ŧђīś ℓîŋќ мαў ľêãδ τб áń úʼnšàƒé ℓоćάŧίоñ. Ĥўрзŗℓĭŋķѕ çâⁿ ъέ ђąřмƒúļ τό ўôця ċómφύŧèґ аňδ ðáťǻ. Ţб ρгøťėçŧ ўòύг ςömφùţĕŕ, ŏŋľỳ čℓΐςķ łίŋκѕ ƒřöм ťŗμѕŧєđ śόυяčêś. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!!</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Őρέй ǻпŷŵãγ !!!</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Śëţťĩпğś !!</value>
@@ -739,6 +769,14 @@
<value>Ẃϊйδοŵš !!</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Δćţíνïŧý īй τаь "{0}" !!! !!!</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Δсŧìνιŧý įņ ţªь "{0}" (ŵϊņδόώ "{1}") !!! !!! !!! !</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Фφĕń ª пёẅ ţâь ίи ğīνęņ ѕŧāятĩлğ δįŗęćтŏяγ !!! !!! !!! !!! </value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>∆çťíνĕ рåⁿэ мôνеð ťб "{0}" ţав !!! !!! !!!</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>"{0}" ťāъ мōνęđ τŏ "{1}" шΐπδŏẅ !!! !!! !!!</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>"{0}" тąь mǿνєđ ŧσ ήèώ ẅĩŋďøẃ !!! !!! !!!</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Λςťìνє рáиė mόνéð ťб "{0}" ŵîńđθω !!! !!! !!! </value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Αĉťįνέ ρªņз mσνёđ τǿ ήёẃ ẃîпďǿω !!! !!! !!!</value>
@@ -875,10 +913,10 @@
<value>Ĩƒ šęţ, ŧнĕ ¢ömmдлδ ŵîĺł ьέ åφрєйδĕđ τσ ŧђė рřŏƒїłє'ş đзƒªūľţ ¢οmмăńδ іñѕţέáđ øƒ ѓēρļąċĭлĝ їţ. !!! !!! !!! !!! !!! !!! !!! !!! !!! !</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Γēѕŧâяŧ ćǿńńēčťїöл !!! !!</value>
<value>Γēѕŧâяŧ ŝєѕѕïσⁿ !!! !</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Γėşťáгţ ŧħ℮ ãčтĩνέ ρăйё сǿηńëςтιóņ !!! !!! !!! !</value>
<value>Γėşťáгţ ŧħ℮ ŝёšŝīőń įй τђ℮ ăċţΐνе φǻñē !!! !!! !!! !!</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Šņíрρēťş !!</value>

View File

@@ -496,24 +496,48 @@
<value>Уведомления третьих лиц</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>Отмена</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>Закрыть все</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>Закрыть все окна?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>Отмена</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>Закрыть все</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>Закрыть все вкладки?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>Закрыть все</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>Закрыть эту вкладку?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>Закрыть вкладку</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>Закрыть эту панель?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>Закрыть область</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>Закрыть эти вкладки?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>Закрыть вкладки</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>Закрыть эти панели?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>Закрыть панели</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>Больше не спрашивать</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>Отмена</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>Этот тип связи в настоящее время не поддерживается:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>Отмена</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>Эта ссылка может привести к небезопасному расположению. Гиперссылки могут нанести вред компьютеру и данным. Чтобы защитить компьютер, щелкните ссылки только из надежных источников.</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>Все равно открыть</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>Параметры</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Активность на вкладке "{0}"</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Активность на вкладке "{0}" (окно "{1}")</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>Открыть новую вкладку в указанном начальном каталоге</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>Активная область перемещена на вкладку "{0}"</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>Вкладка "{0}" перемещена в окно "{1}"</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Вкладка "{0}" перемещена в новое окно</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>Активная область перемещена в окно "{0}"</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Активная область перемещена в новое окно</value>
@@ -875,10 +913,10 @@
<value>Если этот параметр настроен, команда будет добавлена к стандартной команде профиля, а не заменит ее.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Перезапустить подключение</value>
<value>Перезапустить сеанс</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Перезапустить соединение с активной панелью.</value>
<value>Перезапустите сеанс в активной панели</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>Фрагменты</value>

View File

@@ -496,24 +496,48 @@
<value>第三方通知</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>取消</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>全部关闭</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>是否要关闭所有窗口?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>取消</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>全部关闭</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>是否要关闭所有标签页?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>全部关闭</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>是否要关闭此选项卡?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>关闭选项卡</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>是否要关闭此窗格?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>关闭窗格</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>是否要关闭这些选项卡?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>关闭选项卡</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>是否要关闭这些窗格?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>关闭窗格</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>不再询问</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>取消</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>当前不支持此链接类型:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>取消</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>此链接可能会导致不安全的位置。超链接可能对你的计算机和数据有害。若要保护你的计算机,请仅单击来自受信任源的链接。</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>仍然打开</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>设置</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>选项卡“{0}”中的活动</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>选项卡“{0}”(窗口“{1}”)中的活动</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>在给定的起始目录中打开新选项卡</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>活动窗格已移动到“{0}”选项卡</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>“{0}”选项卡已移动到“{1}”窗口</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>“{0}”选项卡已移动到新窗口</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>活动窗格已移动到“{0}”选项卡</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>活动窗格已移动到新窗口</value>
@@ -875,10 +913,10 @@
<value>如果设置,该命令将追加到配置文件的默认命令,而不是替换它。</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>重新启动连接</value>
<value>重启会话</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>重新启动活动窗格连接</value>
<value>重活动窗格中的会话</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>片段</value>

View File

@@ -496,24 +496,48 @@
<value>第三方注意事項</value>
<comment>A hyperlink name for the Terminal's third-party notices</comment>
</data>
<data name="QuitDialog.CloseButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_Cancel" xml:space="preserve">
<value>取消</value>
</data>
<data name="QuitDialog.PrimaryButtonText" xml:space="preserve">
<value>全部關閉</value>
</data>
<data name="QuitDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllTitle" xml:space="preserve">
<value>您要關閉所有視窗嗎?</value>
</data>
<data name="CloseAllDialog.CloseButtonText" xml:space="preserve">
<value>取消</value>
</data>
<data name="CloseAllDialog.PrimaryButtonText" xml:space="preserve">
<data name="ConfirmCloseDialog_CloseAllPrimary" xml:space="preserve">
<value>全部關閉</value>
</data>
<data name="CloseAllDialog.Title" xml:space="preserve">
<data name="ConfirmCloseDialog_WindowTitle" xml:space="preserve">
<value>您要關閉所有索引標籤嗎?</value>
</data>
<data name="ConfirmCloseDialog_WindowPrimary" xml:space="preserve">
<value>全部關閉</value>
</data>
<data name="ConfirmCloseDialog_TabTitle" xml:space="preserve">
<value>是否要關閉此索引標籤?</value>
</data>
<data name="ConfirmCloseDialog_TabPrimary" xml:space="preserve">
<value>關閉索引標籤</value>
</data>
<data name="ConfirmCloseDialog_PaneTitle" xml:space="preserve">
<value>是否要關閉此窗格?</value>
</data>
<data name="ConfirmCloseDialog_PanePrimary" xml:space="preserve">
<value>關閉窗格</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsTitle" xml:space="preserve">
<value>是否要關閉這些索引標籤?</value>
</data>
<data name="ConfirmCloseDialog_MultipleTabsPrimary" xml:space="preserve">
<value>關閉索引標籤</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesTitle" xml:space="preserve">
<value>是否要關閉這些窗格?</value>
</data>
<data name="ConfirmCloseDialog_MultiplePanesPrimary" xml:space="preserve">
<value>關閉窗格</value>
</data>
<data name="DontAskAgainCheckBox.Content" xml:space="preserve">
<value>不要再問我</value>
</data>
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
<value>取消</value>
</data>
@@ -669,9 +693,15 @@
<data name="UnsupportedSchemeText" xml:space="preserve">
<value>目前不支援此連結類型:</value>
</data>
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
<data name="UriErrorDialog.CloseButtonText" xml:space="preserve">
<value>取消</value>
</data>
<data name="UnsafeUrlConfirmText" xml:space="preserve">
<value>此連結可能通往不安全地點。超連結可能對你的電腦和資料造成傷害。為了保護你的電腦,只點擊來自可信來源的連結。</value>
</data>
<data name="UnsafeUrlConfirmAllowAction" xml:space="preserve">
<value>一律開啟</value>
</data>
<data name="SettingsTab" xml:space="preserve">
<value>設定</value>
</data>
@@ -739,6 +769,14 @@
<value>Windows</value>
<comment>This is displayed as a label for the context menu item that holds the submenu of available windows.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>索引標籤「{0}」中的活動</value>
<comment>{0} is the tab title. Shown as the body of a desktop notification when tab activity is detected.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>索引標籤「{0}」(視窗「{1}」) 中的活動</value>
<comment>{0} is the tab title, {1} is the window name. Shown as the body of a desktop notification when tab activity is detected and the window has a name.</comment>
</data>
<data name="DropPathTabRun.Text" xml:space="preserve">
<value>開啟指定起始目錄中的新索引標籤</value>
</data>
@@ -845,11 +883,11 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>活動窗格已移動至「{0}」索引標籤</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>「{0}」索引標籤已移至「{1}」視窗</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>「{0}」索引標籤已移至新視窗</value>
@@ -861,7 +899,7 @@
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
<value>活動窗格已移動至「{0}」視窗</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>活動窗格已移至新視窗</value>
@@ -875,10 +913,10 @@
<value>如果設定,命令會附加到設定檔的預設命令,而不是取代命令。</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>重新啟動連線</value>
<value>重新啟動工作模式</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>重新啟動使用中窗格連線</value>
<value>使用中窗格重新啟動工作階段</value>
</data>
<data name="SnippetPaneTitle.Text" xml:space="preserve">
<value>片斷</value>

View File

@@ -686,8 +686,8 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Helper method for retrieving the action from a command the user
// selected, and dispatching that command. Also fires a tracelogging event
// - Helper method to retrieve the action from the user selected command,
// and dispatch that command. Also fires a tracelogging event
// indicating that the user successfully found the action they were
// looking for.
// Arguments:

View File

@@ -35,7 +35,6 @@ namespace winrt::TerminalApp::implementation
_activePane = nullptr;
_closePaneMenuItem.Visibility(WUX::Visibility::Collapsed);
_restartConnectionMenuItem.Visibility(WUX::Visibility::Collapsed);
auto firstId = _nextPaneId;
@@ -86,6 +85,7 @@ namespace winrt::TerminalApp::implementation
_MakeTabViewItem();
_CreateContextMenu();
_UpdateMenuItemStates();
_headerControl.TabStatus(_tabStatus);
@@ -654,7 +654,7 @@ namespace winrt::TerminalApp::implementation
_activePane = original;
// Add a event handlers to the new panes' GotFocus event. When the pane
// Add event handlers to the new panes' GotFocus event. When the pane
// gains focus, we'll mark it as the new active pane.
_AttachEventHandlersToPane(original);
@@ -844,14 +844,14 @@ namespace winrt::TerminalApp::implementation
// Arguments:
// - direction: The direction to move the separator in.
// Return Value:
// - <none>
void Tab::ResizePane(const ResizeDirection& direction)
// - whether a pane was resized
bool Tab::ResizePane(const ResizeDirection& direction)
{
ASSERT_UI_THREAD();
// NOTE: This _must_ be called on the root pane, so that it can propagate
// throughout the entire tree.
_rootPane->ResizePane(direction);
return _rootPane->ResizePane(direction);
}
// Method Description:
@@ -1148,6 +1148,14 @@ namespace winrt::TerminalApp::implementation
tab->TabRaiseVisualBell.raise();
}
// Send a desktop toast notification if requested, but only if
// the pane isn't already in the belled state. This prevents
// sending repeated toasts for repeated BEL characters.
if (bellArgs.SendNotification() && !tab->_tabStatus.BellIndicator())
{
tab->TabToastNotificationRequested.raise(tab->Title(), L"", sender);
}
// Show the bell indicator in the tab header
tab->ShowBellIndicator(true);
@@ -1166,6 +1174,18 @@ namespace winrt::TerminalApp::implementation
events.RestartTerminalRequested = terminal.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &Tab::_bubbleRestartTerminalRequested });
}
events.NotificationRequested = content.NotificationRequested(
winrt::auto_revoke,
[dispatcher, weakThis](TerminalApp::IPaneContent sender, auto notifArgs) -> safe_void_coroutine {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (const auto tab{ weakThisCopy.get() })
{
const auto title = notifArgs.Title().empty() ? tab->Title() : notifArgs.Title();
tab->TabToastNotificationRequested.raise(title, notifArgs.Body(), sender);
}
});
if (_tabStatus.IsInputBroadcastActive())
{
if (const auto& termContent{ content.try_as<TerminalApp::TerminalPaneContent>() })
@@ -1254,7 +1274,7 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Set an indicator on the tab if any pane is in a closed connection state.
// - Show/hide the Restart Connection context menu entry depending on active pane's state.
// - Show/hide the Restart Session context menu entry depending on active pane's state.
// Arguments:
// - <none>
// Return Value:
@@ -1271,13 +1291,6 @@ namespace winrt::TerminalApp::implementation
_tabStatus.IsConnectionClosed(isClosed);
}
if (_activePane)
{
_restartConnectionMenuItem.Visibility(_activePane->IsConnectionClosed() ?
WUX::Visibility::Visible :
WUX::Visibility::Collapsed);
}
}
void Tab::_RestartActivePaneConnection()
@@ -1348,6 +1361,22 @@ namespace winrt::TerminalApp::implementation
}
});
}
_UpdateMenuItemStates();
}
void Tab::_UpdateMenuItemStates()
{
// Terminal-specific menu items
const auto content = _activePane ? _activePane->GetContent() : nullptr;
const auto isTerm = content && content.try_as<winrt::TerminalApp::TerminalPaneContent>() != nullptr;
_duplicateTabMenuItem.IsEnabled(isTerm);
_exportTabMenuItem.IsEnabled(isTerm);
_findMenuItem.IsEnabled(isTerm);
_restartConnectionMenuItem.IsEnabled(isTerm);
// Snippets Pane can technically be split
_splitTabMenuItem.IsEnabled(isTerm || (content && content.try_as<winrt::TerminalApp::SnippetsPaneContent>() != nullptr));
}
// Method Description:
@@ -1652,106 +1681,100 @@ namespace winrt::TerminalApp::implementation
Automation::AutomationProperties::SetHelpText(renameTabMenuItem, renameTabToolTip);
}
Controls::MenuFlyoutItem duplicateTabMenuItem;
{
// "Duplicate tab"
Controls::FontIcon duplicateTabSymbol;
duplicateTabSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
duplicateTabSymbol.Glyph(L"\xF5ED");
duplicateTabMenuItem.Click({ get_weak(), &Tab::_duplicateTabClicked });
duplicateTabMenuItem.Text(RS_(L"DuplicateTabText"));
duplicateTabMenuItem.Icon(duplicateTabSymbol);
_duplicateTabMenuItem.Click({ get_weak(), &Tab::_duplicateTabClicked });
_duplicateTabMenuItem.Text(RS_(L"DuplicateTabText"));
_duplicateTabMenuItem.Icon(duplicateTabSymbol);
const auto duplicateTabToolTip = RS_(L"DuplicateTabToolTip");
WUX::Controls::ToolTipService::SetToolTip(duplicateTabMenuItem, box_value(duplicateTabToolTip));
Automation::AutomationProperties::SetHelpText(duplicateTabMenuItem, duplicateTabToolTip);
WUX::Controls::ToolTipService::SetToolTip(_duplicateTabMenuItem, box_value(duplicateTabToolTip));
Automation::AutomationProperties::SetHelpText(_duplicateTabMenuItem, duplicateTabToolTip);
}
Controls::MenuFlyoutItem splitTabMenuItem;
{
// "Split tab"
Controls::FontIcon splitTabSymbol;
splitTabSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
splitTabSymbol.Glyph(L"\xF246"); // ViewDashboard
splitTabMenuItem.Click({ get_weak(), &Tab::_splitTabClicked });
splitTabMenuItem.Text(RS_(L"SplitTabText"));
splitTabMenuItem.Icon(splitTabSymbol);
_splitTabMenuItem.Click({ get_weak(), &Tab::_splitTabClicked });
_splitTabMenuItem.Text(RS_(L"SplitTabText"));
_splitTabMenuItem.Icon(splitTabSymbol);
const auto splitTabToolTip = RS_(L"SplitTabToolTip");
WUX::Controls::ToolTipService::SetToolTip(splitTabMenuItem, box_value(splitTabToolTip));
Automation::AutomationProperties::SetHelpText(splitTabMenuItem, splitTabToolTip);
WUX::Controls::ToolTipService::SetToolTip(_splitTabMenuItem, box_value(splitTabToolTip));
Automation::AutomationProperties::SetHelpText(_splitTabMenuItem, splitTabToolTip);
}
Controls::MenuFlyoutItem closePaneMenuItem = _closePaneMenuItem;
{
// "Close pane"
closePaneMenuItem.Click({ get_weak(), &Tab::_closePaneClicked });
closePaneMenuItem.Text(RS_(L"ClosePaneText"));
_closePaneMenuItem.Click({ get_weak(), &Tab::_closePaneClicked });
_closePaneMenuItem.Text(RS_(L"ClosePaneText"));
const auto closePaneToolTip = RS_(L"ClosePaneToolTip");
WUX::Controls::ToolTipService::SetToolTip(closePaneMenuItem, box_value(closePaneToolTip));
Automation::AutomationProperties::SetHelpText(closePaneMenuItem, closePaneToolTip);
WUX::Controls::ToolTipService::SetToolTip(_closePaneMenuItem, box_value(closePaneToolTip));
Automation::AutomationProperties::SetHelpText(_closePaneMenuItem, closePaneToolTip);
}
Controls::MenuFlyoutItem exportTabMenuItem;
{
// "Export tab"
Controls::FontIcon exportTabSymbol;
exportTabSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
exportTabSymbol.Glyph(L"\xE74E"); // Save
exportTabMenuItem.Click({ get_weak(), &Tab::_exportTextClicked });
exportTabMenuItem.Text(RS_(L"ExportTabText"));
exportTabMenuItem.Icon(exportTabSymbol);
_exportTabMenuItem.Click({ get_weak(), &Tab::_exportTextClicked });
_exportTabMenuItem.Text(RS_(L"ExportTabText"));
_exportTabMenuItem.Icon(exportTabSymbol);
const auto exportTabToolTip = RS_(L"ExportTabToolTip");
WUX::Controls::ToolTipService::SetToolTip(exportTabMenuItem, box_value(exportTabToolTip));
Automation::AutomationProperties::SetHelpText(exportTabMenuItem, exportTabToolTip);
WUX::Controls::ToolTipService::SetToolTip(_exportTabMenuItem, box_value(exportTabToolTip));
Automation::AutomationProperties::SetHelpText(_exportTabMenuItem, exportTabToolTip);
}
Controls::MenuFlyoutItem findMenuItem;
{
// "Find"
Controls::FontIcon findSymbol;
findSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
findSymbol.Glyph(L"\xF78B"); // SearchMedium
findMenuItem.Click({ get_weak(), &Tab::_findClicked });
findMenuItem.Text(RS_(L"FindText"));
findMenuItem.Icon(findSymbol);
_findMenuItem.Click({ get_weak(), &Tab::_findClicked });
_findMenuItem.Text(RS_(L"FindText"));
_findMenuItem.Icon(findSymbol);
const auto findToolTip = RS_(L"FindToolTip");
WUX::Controls::ToolTipService::SetToolTip(findMenuItem, box_value(findToolTip));
Automation::AutomationProperties::SetHelpText(findMenuItem, findToolTip);
WUX::Controls::ToolTipService::SetToolTip(_findMenuItem, box_value(findToolTip));
Automation::AutomationProperties::SetHelpText(_findMenuItem, findToolTip);
}
Controls::MenuFlyoutItem restartConnectionMenuItem = _restartConnectionMenuItem;
{
// "Restart connection"
// "Restart session"
Controls::FontIcon restartConnectionSymbol;
restartConnectionSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
restartConnectionSymbol.Glyph(L"\xE72C");
restartConnectionMenuItem.Click([weakThis](auto&&, auto&&) {
_restartConnectionMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_RestartActivePaneConnection();
}
});
restartConnectionMenuItem.Text(RS_(L"RestartConnectionText"));
restartConnectionMenuItem.Icon(restartConnectionSymbol);
_restartConnectionMenuItem.Text(RS_(L"RestartConnectionText"));
_restartConnectionMenuItem.Icon(restartConnectionSymbol);
const auto restartConnectionToolTip = RS_(L"RestartConnectionToolTip");
WUX::Controls::ToolTipService::SetToolTip(restartConnectionMenuItem, box_value(restartConnectionToolTip));
Automation::AutomationProperties::SetHelpText(restartConnectionMenuItem, restartConnectionToolTip);
WUX::Controls::ToolTipService::SetToolTip(_restartConnectionMenuItem, box_value(restartConnectionToolTip));
Automation::AutomationProperties::SetHelpText(_restartConnectionMenuItem, restartConnectionToolTip);
}
// Build the menu
@@ -1759,16 +1782,16 @@ namespace winrt::TerminalApp::implementation
Controls::MenuFlyoutSeparator menuSeparator;
contextMenuFlyout.Items().Append(chooseColorMenuItem);
contextMenuFlyout.Items().Append(renameTabMenuItem);
contextMenuFlyout.Items().Append(duplicateTabMenuItem);
contextMenuFlyout.Items().Append(splitTabMenuItem);
contextMenuFlyout.Items().Append(_duplicateTabMenuItem);
contextMenuFlyout.Items().Append(_splitTabMenuItem);
_AppendMoveMenuItems(contextMenuFlyout);
contextMenuFlyout.Items().Append(exportTabMenuItem);
contextMenuFlyout.Items().Append(findMenuItem);
contextMenuFlyout.Items().Append(restartConnectionMenuItem);
contextMenuFlyout.Items().Append(_exportTabMenuItem);
contextMenuFlyout.Items().Append(_findMenuItem);
contextMenuFlyout.Items().Append(_restartConnectionMenuItem);
contextMenuFlyout.Items().Append(menuSeparator);
auto closeSubMenu = _AppendCloseMenuItems(contextMenuFlyout);
closeSubMenu.Items().Append(closePaneMenuItem);
closeSubMenu.Items().Append(_closePaneMenuItem);
// GH#5750 - When the context menu is dismissed with ESC, toss the focus
// back to our control.
@@ -2098,7 +2121,7 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Calculates if the tab is read-only.
// The tab is considered read-only if one of the panes is read-only.
// If after the calculation the tab is read-only we hide the close button on the tab view item
// If, after the calculation, the tab is read-only we hide the close button on the tab view item
void Tab::_RecalculateAndApplyReadOnly()
{
const auto control = GetActiveTerminalControl();
@@ -2125,7 +2148,7 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Creates a text for the title run in the tool tip by returning tab title
// or <profile name>: <tab title> in the case the profile name differs from the title
// or <profile name>: <tab title> if the profile name differs from the title
// Arguments:
// - <none>
// Return Value:
@@ -2353,7 +2376,7 @@ namespace winrt::TerminalApp::implementation
auto deselectedTabColor = color.with_alpha(77); // 255 * .3 = 77
// If we DON'T have a color set from the color picker, or the profile's
// tabColor, but we do have a unfocused color in the theme, use the
// tabColor, but if we have an unfocused color in the theme, use the
// unfocused theme color here instead.
if (!GetTabColor().has_value() &&
_unfocusedThemeColor != nullptr)

View File

@@ -53,7 +53,7 @@ namespace winrt::TerminalApp::implementation
const float splitSize,
winrt::Windows::Foundation::Size availableSpace) const;
void ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool SwapPane(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool FocusPane(const uint32_t id);
@@ -121,6 +121,7 @@ namespace winrt::TerminalApp::implementation
til::typed_event<TerminalApp::Tab, IInspectable> ActivePaneChanged;
til::event<winrt::delegate<>> TabRaiseVisualBell;
til::event<winrt::delegate<winrt::hstring /*title*/, winrt::hstring /*body*/, winrt::TerminalApp::IPaneContent /*content*/>> TabToastNotificationRequested;
til::typed_event<IInspectable, IInspectable> TaskbarProgressChanged;
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
@@ -140,11 +141,17 @@ namespace winrt::TerminalApp::implementation
static constexpr double HeaderRenameBoxWidthTitleLength{ std::numeric_limits<double>::infinity() };
winrt::Windows::UI::Xaml::FocusState _focusState{ winrt::Windows::UI::Xaml::FocusState::Unfocused };
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeOtherTabsMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _duplicateTabMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _splitTabMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveToNewWindowMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveRightMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _moveLeftMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _exportTabMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _findMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _restartConnectionMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeOtherTabsMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{};
winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closePaneMenuItem{};
winrt::TerminalApp::ShortcutActionDispatch _dispatch;
Microsoft::Terminal::Settings::Model::IActionMapView _actionMap{ nullptr };
winrt::hstring _keyChord{};
@@ -159,9 +166,6 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<Pane> _activePane{ nullptr };
std::shared_ptr<Pane> _zoomedPane{ nullptr };
Windows::UI::Xaml::Controls::MenuFlyoutItem _closePaneMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem _restartConnectionMenuItem;
winrt::Microsoft::Terminal::Settings::Model::IconStyle _lastIconStyle;
winrt::hstring _lastIconPath{};
std::optional<winrt::Windows::UI::Color> _runtimeTabColor{};
@@ -182,6 +186,7 @@ namespace winrt::TerminalApp::implementation
winrt::TerminalApp::IPaneContent::ConnectionStateChanged_revoker ConnectionStateChanged;
winrt::TerminalApp::IPaneContent::ReadOnlyChanged_revoker ReadOnlyChanged;
winrt::TerminalApp::IPaneContent::FocusRequested_revoker FocusRequested;
winrt::TerminalApp::IPaneContent::NotificationRequested_revoker NotificationRequested;
// These events literally only apply if the content is a TermControl.
winrt::Microsoft::Terminal::Control::TermControl::KeySent_revoker KeySent;
@@ -220,6 +225,7 @@ namespace winrt::TerminalApp::implementation
void _AttachEventHandlersToPane(std::shared_ptr<Pane> pane);
void _UpdateActivePane(std::shared_ptr<Pane> pane);
void _UpdateMenuItemStates();
winrt::hstring _GetActiveTitle() const;
@@ -230,8 +236,6 @@ namespace winrt::TerminalApp::implementation
void _UpdateConnectionClosedState();
void _RestartActivePaneConnection();
void _DuplicateTab();
winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush();
void _MakeTabViewItem();

View File

@@ -17,6 +17,7 @@
#include "TabRowControl.h"
#include "DebugTapConnection.h"
#include "DesktopNotification.h"
#include "..\TerminalSettingsModel\FileUtils.h"
#include "../TerminalSettingsAppAdapterLib/TerminalSettings.h"
@@ -150,6 +151,18 @@ namespace winrt::TerminalApp::implementation
}
});
// When a tab requests a desktop toast notification, send the toast
// and handle activation by summoning this window and switching to the tab.
newTabImpl->TabToastNotificationRequested([weakThis{ get_weak() }, weakTab{ newTabImpl->get_weak() }](const winrt::hstring& title, const winrt::hstring& body, const winrt::TerminalApp::IPaneContent& content) {
if (const auto page{ weakThis.get() })
{
if (const auto tab{ weakTab.get() })
{
page->_SendDesktopNotification(title, body, tab, content);
}
}
});
auto tabViewItem = newTabImpl->TabViewItem();
_tabView.TabItems().InsertAt(insertPosition, tabViewItem);
@@ -394,7 +407,9 @@ namespace winrt::TerminalApp::implementation
// - Removes the tab (both TerminalControl and XAML) after prompting for approval
// Arguments:
// - tab: the tab to remove
winrt::Windows::Foundation::IAsyncAction TerminalPage::_HandleCloseTabRequested(winrt::TerminalApp::Tab tab)
// - skipConfirmClose: if true, skip the confirmOnClose check. Used when
// an aggregate confirmation has already been shown (i.e. close other tabs)
winrt::Windows::Foundation::IAsyncAction TerminalPage::_HandleCloseTabRequested(winrt::TerminalApp::Tab tab, bool skipConfirmClose)
{
winrt::com_ptr<TerminalPage> strong;
@@ -413,6 +428,24 @@ namespace winrt::TerminalApp::implementation
}
}
// Skip the per-tab confirmOnClose check when the caller has already
// shown an aggregate confirmation dialog (e.g. _RemoveTabs).
if (!skipConfirmClose)
{
const auto tabImpl = _GetTabImpl(tab);
if (tabImpl && _ShouldWarnOnCloseTab(tabImpl))
{
const auto weak = get_weak();
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::Tab);
strong = weak.get();
if (!strong || warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
}
auto t = winrt::get_self<implementation::Tab>(tab);
auto actions = t->BuildStartupActions(BuildStartupKind::None);
_AddPreviouslyClosedPaneOrTab(std::move(actions));
@@ -782,6 +815,26 @@ namespace winrt::TerminalApp::implementation
if (const auto pane{ activeTab->GetActivePane() })
{
const auto weak = get_weak();
// Check if we should warn before closing a single pane
// (only triggers on Always — Automatic doesn't warn for single pane)
const auto setting = _settings.GlobalSettings().ConfirmOnClose();
if (setting == ConfirmOnClose::Always)
{
// If this is the last pane, closing it closes the tab,
// so use the tab dialog text instead.
const auto kind = activeTab->GetLeafPaneCount() == 1 ? ConfirmCloseDialogKind::Tab : ConfirmCloseDialogKind::Pane;
auto warningResult = co_await _ShowConfirmCloseDialog(kind);
// Hold a strong reference to `this` for the rest of the
// method; we may be the last holder after `co_await`.
auto strong = weak.get();
if (!strong || warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
if (co_await _PaneConfirmCloseReadOnly(pane))
{
if (const auto strong = weak.get())
@@ -795,10 +848,37 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Close all panes with the given IDs sequentially.
// - Shows a single aggregate confirmation dialog upfront if the confirmOnClose setting warrants it.
// Arguments:
// - weakTab: weak reference to the tab that the pane belongs to.
// - weakTab: weak reference to the tab that the panes belong to.
// - paneIds: collection of the IDs of the panes that are marked for removal.
void TerminalPage::_ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds)
safe_void_coroutine TerminalPage::_ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds)
{
// Show a single aggregate confirmation for closing multiple panes.
if (_settings.GlobalSettings().ConfirmOnClose() != ConfirmOnClose::Never)
{
const auto weak = get_weak();
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::MultiplePanes);
// Hold a strong reference to `this` after the co_await; we may
// be the last holder if the page was being torn down.
auto strong = weak.get();
if (!strong || warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
_CloseRemainingPanes(weakTab, std::move(paneIds));
}
// Method Description:
// - Recursively closes panes by ID, chaining each close via the
// ClosedByParent callback. Called after confirmation has already
// been handled by _ClosePanes.
// Arguments:
// - weakTab: weak reference to the tab that the panes belong to
// - paneIds: remaining pane IDs to close
void TerminalPage::_CloseRemainingPanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds)
{
if (auto strongTab{ weakTab.get() })
{
@@ -813,10 +893,9 @@ namespace winrt::TerminalApp::implementation
pane->ClosedByParent([ids{ std::move(paneIds) }, weakThis{ get_weak() }, weakTab]() {
if (auto strongThis{ weakThis.get() })
{
strongThis->_ClosePanes(weakTab, std::move(ids));
strongThis->_CloseRemainingPanes(weakTab, std::move(ids));
}
});
// Close the pane which will eventually trigger the closed by parent event
_HandleClosePaneRequested(pane);
break;
@@ -841,18 +920,37 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Closes provided tabs one by one
// - Shows a single aggregate confirmation dialog upfront if the confirmOnClose setting warrants it.
// Arguments:
// - tabs - tabs to remove
safe_void_coroutine TerminalPage::_RemoveTabs(const std::vector<winrt::TerminalApp::Tab> tabs)
{
if (tabs.empty())
{
co_return;
}
// Show a single aggregate confirmation instead of per-tab dialogs.
const auto weak = get_weak();
if (_settings.GlobalSettings().ConfirmOnClose() != ConfirmOnClose::Never)
{
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::MultipleTabs);
// Hold a strong reference to `this` after the co_await so that
// the for-loop below can safely dispatch on us.
auto strong = weak.get();
if (!strong || warningResult != ContentDialogResult::Primary)
{
co_return;
}
}
for (auto& tab : tabs)
{
winrt::Windows::Foundation::IAsyncAction action{ nullptr };
if (const auto strong = weak.get())
{
action = _HandleCloseTabRequested(tab);
action = _HandleCloseTabRequested(tab, /*skipConfirmClose*/ true);
}
if (!action)
@@ -1185,4 +1283,128 @@ namespace winrt::TerminalApp::implementation
{
return _tabs.Size() > 1;
}
// Method Description:
// - Attempts to find and focus the given tab in this window.
// Arguments:
// - tab: The tab to focus.
// Return Value:
// - true if the tab was found and focused, false otherwise.
bool TerminalPage::FocusTab(const winrt::TerminalApp::Tab& tab)
{
if (const auto tabIndex{ _GetTabIndex(tab) })
{
_SelectTab(tabIndex.value());
return true;
}
return false;
}
// Method Description:
// - Sends a desktop toast notification with the given title and body.
// When the toast is activated (clicked), the window is summoned and
// the originating tab is focused.
// Arguments:
// - tabTitle: The title to display in the notification.
// - body: The body text. If empty, a standard tab-activity message is built.
// - tab: The tab to switch to when the toast is activated.
void TerminalPage::_SendDesktopNotification(const winrt::hstring& tabTitle, const winrt::hstring& body, const winrt::com_ptr<Tab>& tab, const winrt::TerminalApp::IPaneContent& content)
{
// Don't send a notification if the window is focused and the requesting
// pane is the active pane. The user is already looking at it.
if (_activated && tab == _GetFocusedTabImpl())
{
if (const auto activePane{ tab->GetActivePane() })
{
if (activePane->GetContent() == content)
{
return;
}
}
}
// Build the notification message.
// If a custom body is provided (e.g. from OSC 777), use the title/body directly.
// Otherwise, build the standard tab-activity notification message.
winrt::hstring notificationTitle;
winrt::hstring message;
if (!body.empty())
{
notificationTitle = tabTitle;
message = body;
}
else
{
// Use the window name if available for context; otherwise just use the tab title.
// Use the raw WindowName (not WindowNameForDisplay) so we don't include
// the "<unnamed window>" placeholder in the notification body.
const auto windowName = _WindowProperties ? _WindowProperties.WindowName() : winrt::hstring{};
if (!windowName.empty())
{
message = RS_fmt(L"NotificationMessage_TabActivityInWindow", std::wstring_view{ tabTitle }, std::wstring_view{ windowName });
}
else
{
message = RS_fmt(L"NotificationMessage_TabActivity", std::wstring_view{ tabTitle });
}
notificationTitle = CascadiaSettings::ApplicationDisplayName();
}
// Use the Tab object's identity hash as a stable toast tag.
// This survives tab reordering and cross-window moves.
const auto tabHash = std::hash<winrt::Windows::Foundation::IUnknown>{}(*tab);
const hstring tabTag{ fmt::format(FMT_COMPILE(L"wt-tab-{:016x}"), tabHash) };
const implementation::DesktopNotificationArgs args{
.Title = notificationTitle,
.Message = message,
.Tag = tabTag
};
implementation::DesktopNotification::SendNotification(args, [weakThis{ get_weak() }, weakTab{ tab->get_weak() }, weakContent{ winrt::make_weak(content) }]() {
if (const auto page{ weakThis.get() })
{
// The toast Activated callback runs on a background thread.
// Marshal to the UI thread for tab focus and window summon.
page->Dispatcher().RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [weakPage{ page->get_weak() }, weakTab, weakContent]() {
if (const auto p{ weakPage.get() })
{
if (const auto t{ weakTab.get() })
{
// Try to find and focus the tab in this window first.
if (const auto tabIndex{ p->_GetTabIndex(*t) })
{
p->SummonWindowRequested.raise(nullptr, nullptr);
p->_SelectTab(tabIndex.value());
// Focus the specific pane that raised the notification.
if (const auto paneContent{ weakContent.get() })
{
const auto rootPane = t->GetRootPane();
rootPane->WalkTree([&](const auto& pane) {
if (pane->GetContent() == paneContent)
{
rootPane->FocusPane(pane);
}
});
}
}
else
{
// The tab may have moved to another window.
// Raise FocusTabRequested so the emperor can
// search all windows for it.
p->FocusTabRequested.raise(nullptr, *t);
}
}
else
{
// Tab was closed. Just summon this window.
p->SummonWindowRequested.raise(nullptr, nullptr);
}
}
});
}
});
}
}

View File

@@ -174,6 +174,7 @@
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClInclude>
<ClInclude Include="Toast.h" />
<ClInclude Include="DesktopNotification.h" />
<ClInclude Include="TerminalSettingsCache.h" />
<ClInclude Include="SuggestionsControl.h">
<DependentUpon>SuggestionsControl.xaml</DependentUpon>
@@ -287,6 +288,7 @@
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="Toast.cpp" />
<ClCompile Include="DesktopNotification.cpp" />
<ClCompile Include="TerminalSettingsCache.cpp" />
<ClCompile Include="SuggestionsControl.cpp">
<DependentUpon>SuggestionsControl.xaml</DependentUpon>

View File

@@ -884,26 +884,78 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Displays a dialog to warn the user that they are about to close all open windows.
// Once the user clicks the OK button, shut down the application.
// If cancel is clicked, the dialog will close.
// - Displays the unified close confirmation dialog configured for the
// given scenario. Resets the "don't ask me again" checkbox before showing.
// If the user confirms and checked "don't ask me again", sets
// confirmOnClose to Never and writes settings to disk.
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens. See _ShowDialog for details
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowQuitDialog()
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowConfirmCloseDialog(ConfirmCloseDialogKind kind)
{
return _ShowDialogHelper(L"QuitDialog");
}
// Load the dialog (triggers x:Load) and configure its strings.
const auto dialog = FindName(L"ConfirmCloseDialog").as<ContentDialog>();
// Method Description:
// - Displays a dialog for warnings found while closing the terminal app using
// key binding with multiple tabs opened. Display messages to warn user
// that more than 1 tab is opened, and once the user clicks the OK button, remove
// all the tabs and shut down and app. If cancel is clicked, the dialog will close
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens. See _ShowDialog for details
winrt::Windows::Foundation::IAsyncOperation<ContentDialogResult> TerminalPage::_ShowCloseWarningDialog()
{
return _ShowDialogHelper(L"CloseAllDialog");
winrt::hstring title;
winrt::hstring primary;
switch (kind)
{
case ConfirmCloseDialogKind::CloseAll:
title = RS_(L"ConfirmCloseDialog_CloseAllTitle");
primary = RS_(L"ConfirmCloseDialog_CloseAllPrimary");
break;
case ConfirmCloseDialogKind::Window:
title = RS_(L"ConfirmCloseDialog_WindowTitle");
primary = RS_(L"ConfirmCloseDialog_WindowPrimary");
break;
case ConfirmCloseDialogKind::Tab:
title = RS_(L"ConfirmCloseDialog_TabTitle");
primary = RS_(L"ConfirmCloseDialog_TabPrimary");
break;
case ConfirmCloseDialogKind::MultiplePanes:
title = RS_(L"ConfirmCloseDialog_MultiplePanesTitle");
primary = RS_(L"ConfirmCloseDialog_MultiplePanesPrimary");
break;
case ConfirmCloseDialogKind::MultipleTabs:
title = RS_(L"ConfirmCloseDialog_MultipleTabsTitle");
primary = RS_(L"ConfirmCloseDialog_MultipleTabsPrimary");
break;
case ConfirmCloseDialogKind::Pane:
title = RS_(L"ConfirmCloseDialog_PaneTitle");
primary = RS_(L"ConfirmCloseDialog_PanePrimary");
break;
}
dialog.Title(winrt::box_value(title));
dialog.PrimaryButtonText(primary);
dialog.CloseButtonText(RS_(L"ConfirmCloseDialog_Cancel"));
// BODGY: After a ContentDialog is dismissed, FindName() can no longer
// resolve children inside it. Use Content() to get the checkbox directly.
const auto checkbox = dialog.Content().as<CheckBox>();
checkbox.IsChecked(false);
auto result = ContentDialogResult::None;
if (auto presenter{ _dialogPresenter.get() })
{
const auto weak = get_weak();
result = co_await presenter.ShowDialog(dialog);
// ShowDialog blocks until the dialog is dismissed, so it is
// possible for `this` to be torn down while we wait. Re-acquire
// a strong reference before touching any of our state.
const auto strong = weak.get();
if (!strong)
{
co_return ContentDialogResult::None;
}
if (result == ContentDialogResult::Primary && checkbox.IsChecked().Value())
{
_settings.GlobalSettings().ConfirmOnClose(ConfirmOnClose::Never);
_settings.WriteSettingsToDisk();
}
}
co_return result;
}
// Method Description:
@@ -1600,8 +1652,7 @@ namespace winrt::TerminalApp::implementation
// Replace the Starting directory with the CWD, if given
const auto workingDirectory = control.WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
if (Utils::IsValidDirectory(workingDirectory.c_str()))
{
controlSettings.DefaultSettings()->StartingDirectory(workingDirectory);
}
@@ -2210,12 +2261,13 @@ namespace winrt::TerminalApp::implementation
// signal that we want to close everything.
safe_void_coroutine TerminalPage::RequestQuit()
{
if (!_displayingCloseDialog)
const auto setting = _settings.GlobalSettings().ConfirmOnClose();
if (setting != ConfirmOnClose::Never && !_displayingCloseDialog)
{
_displayingCloseDialog = true;
const auto weak = get_weak();
auto warningResult = co_await _ShowQuitDialog();
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::CloseAll);
const auto strong = weak.get();
if (!strong)
{
@@ -2228,9 +2280,9 @@ namespace winrt::TerminalApp::implementation
{
co_return;
}
QuitRequested.raise(nullptr, nullptr);
}
QuitRequested.raise(nullptr, nullptr);
}
void TerminalPage::PersistState()
@@ -2308,12 +2360,59 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Close the terminal app. If there is more
// than one tab opened, show a warning dialog.
// - Determines whether a close-window action should show a confirmation
// dialog, based on the confirmOnClose setting and the current window state.
// Arguments:
// - <none>
// Return Value:
// - true, if a warning dialog should be shown before closing the window
bool TerminalPage::_ShouldWarnOnClose() const
{
const auto setting = _settings.GlobalSettings().ConfirmOnClose();
switch (setting)
{
case ConfirmOnClose::Always:
return true;
case ConfirmOnClose::Automatic:
{
// Warn if there's more than one tab, or the one tab has more than one pane.
return _HasMultipleTabs() || _GetTabImpl(_tabs.GetAt(0))->GetLeafPaneCount() > 1;
}
case ConfirmOnClose::Never:
default:
return false;
}
}
// Method Description:
// - Determines whether closing a specific tab should show a confirmation
// dialog, based on the confirmOnClose setting and the tab's state.
// Arguments:
// - tab: The tab being closed
// Return Value:
// - true, if a warning dialog should be shown before closing the tab
bool TerminalPage::_ShouldWarnOnCloseTab(const winrt::com_ptr<Tab>& tab) const
{
const auto setting = _settings.GlobalSettings().ConfirmOnClose();
switch (setting)
{
case ConfirmOnClose::Always:
return true;
case ConfirmOnClose::Automatic:
// Warn if this tab has more than one pane.
return tab->GetLeafPaneCount() > 1;
case ConfirmOnClose::Never:
default:
return false;
}
}
// Method Description:
// - Close the terminal app. If the confirmOnClose setting indicates we should
// warn for the current window state, show a warning dialog.
safe_void_coroutine TerminalPage::CloseWindow()
{
if (_HasMultipleTabs() &&
_settings.GlobalSettings().ConfirmCloseAllTabs() &&
if (_ShouldWarnOnClose() &&
!_displayingCloseDialog)
{
if (_newTabButton && _newTabButton.Flyout())
@@ -2322,7 +2421,17 @@ namespace winrt::TerminalApp::implementation
}
_DismissTabContextMenus();
_displayingCloseDialog = true;
auto warningResult = co_await _ShowCloseWarningDialog();
const auto weak = get_weak();
auto warningResult = co_await _ShowConfirmCloseDialog(ConfirmCloseDialogKind::Window);
// Hold a strong reference to `this` after the co_await; we may
// be the last holder if the window was already being torn down.
auto strong = weak.get();
if (!strong)
{
co_return;
}
_displayingCloseDialog = false;
if (warningResult != ContentDialogResult::Primary)
@@ -2791,14 +2900,15 @@ namespace winrt::TerminalApp::implementation
// Arguments:
// - direction: The direction to move the separator in.
// Return Value:
// - <none>
void TerminalPage::_ResizePane(const ResizeDirection& direction)
// - whether a pane was resized
bool TerminalPage::_ResizePane(const ResizeDirection& direction)
{
if (const auto tabImpl{ _GetFocusedTabImpl() })
{
_UnZoomIfNeeded();
tabImpl->ResizePane(direction);
return tabImpl->ResizePane(direction);
}
return false;
}
// Method Description:
@@ -2973,7 +3083,11 @@ namespace winrt::TerminalApp::implementation
text = winrt::hstring{ Utils::TrimPaste(text) };
}
if (text.empty())
// LOAD BEARING: Send an empty bracketed paste even if the clipboard was empty.
// Bracketed Paste provides an application a way to know whether the
// user pasted, even if there was no applicable content on it. This
// behavior is observed in GNOME Terminal, among others.
if (!bracketedPaste && text.empty())
{
co_return;
}
@@ -3082,18 +3196,42 @@ namespace winrt::TerminalApp::implementation
}
CATCH_LOG();
void TerminalPage::_OpenHyperlinkHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::OpenHyperlinkEventArgs eventArgs)
safe_void_coroutine TerminalPage::_OpenHyperlinkHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::OpenHyperlinkEventArgs eventArgs)
{
try
{
auto parsed = winrt::Windows::Foundation::Uri(eventArgs.Uri());
auto uriString{ eventArgs.Uri() };
auto parsed = winrt::Windows::Foundation::Uri(uriString);
if (_IsUriSupported(parsed))
{
ShellExecute(nullptr, L"open", eventArgs.Uri().c_str(), nullptr, nullptr, SW_SHOWNORMAL);
bool shouldLaunch{ _IsUriConsideredSomewhatSafe(parsed) };
if (!shouldLaunch)
{
if (auto presenter{ _dialogPresenter.get() })
{
// FindName needs to be called first to actually load the xaml object
auto unopenedUriDialog = FindName(L"UriErrorDialog").try_as<WUX::Controls::ContentDialog>();
// Insert the reason and the URI
unopenedUriDialog.SecondaryButtonText(RS_(L"UnsafeUrlConfirmAllowAction"));
CouldNotOpenUriReason().Text(RS_(L"UnsafeUrlConfirmText"));
UnopenedUri().Text(uriString);
// Show the dialog
auto result = co_await presenter.ShowDialog(unopenedUriDialog);
shouldLaunch = result == ContentDialogResult::Secondary;
}
}
if (shouldLaunch)
{
ShellExecuteW(nullptr, L"open", uriString.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
}
}
else
{
_ShowCouldNotOpenDialog(RS_(L"UnsupportedSchemeText"), eventArgs.Uri());
_ShowCouldNotOpenDialog(RS_(L"UnsupportedSchemeText"), uriString);
}
}
catch (...)
@@ -3113,9 +3251,10 @@ namespace winrt::TerminalApp::implementation
if (auto presenter{ _dialogPresenter.get() })
{
// FindName needs to be called first to actually load the xaml object
auto unopenedUriDialog = FindName(L"CouldNotOpenUriDialog").try_as<WUX::Controls::ContentDialog>();
auto unopenedUriDialog = FindName(L"UriErrorDialog").try_as<WUX::Controls::ContentDialog>();
// Insert the reason and the URI
unopenedUriDialog.SecondaryButtonText({});
CouldNotOpenUriReason().Text(reason);
UnopenedUri().Text(uri);
@@ -3168,6 +3307,30 @@ namespace winrt::TerminalApp::implementation
return true;
}
bool TerminalPage::_IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri)
{
if (parsedUri.SchemeName() == L"http" || parsedUri.SchemeName() == L"https")
{
return true;
}
if (parsedUri.SchemeName() == L"file")
{
static const auto pathext{ wil::TryGetEnvironmentVariableW<std::wstring>(L"PATHEXT") };
const auto filename = parsedUri.Path();
for (const auto& e : til::split_iterator{ std::wstring_view{ pathext }, L';' })
{
if (til::ends_with_insensitive_ascii(filename, e))
{
return false;
}
}
return true;
}
return false;
}
// Important! Don't take this eventArgs by reference, we need to extend the
// lifetime of it to the other side of the co_await!
safe_void_coroutine TerminalPage::_ControlNoticeRaisedHandler(const IInspectable /*sender*/,
@@ -3555,8 +3718,7 @@ namespace winrt::TerminalApp::implementation
profile = GetClosestProfileForDuplicationOfProfile(profile);
controlSettings = Settings::TerminalSettings::CreateWithProfile(_settings, profile);
const auto workingDirectory = tabImpl->GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
if (Utils::IsValidDirectory(workingDirectory.c_str()))
{
controlSettings.DefaultSettings()->StartingDirectory(workingDirectory);
}
@@ -3742,7 +3904,13 @@ namespace winrt::TerminalApp::implementation
// for nulls
if (const auto& connection{ _duplicateConnectionForRestart(paneContent) })
{
paneContent.GetTermControl().Connection(connection);
// Reset the terminal's VT state before attaching the new connection.
// The previous client may have left dirty modes (e.g., bracketed
// paste, mouse tracking, alternate buffer, kitty keyboard) that
// would corrupt input/output for the new shell process.
const auto& termControl = paneContent.GetTermControl();
termControl.HardResetWithoutErase();
termControl.Connection(connection);
connection.Start();
}
}
@@ -4670,7 +4838,7 @@ namespace winrt::TerminalApp::implementation
// Function Description:
// - Helper to launch a new WT instance elevated. It'll do this by spawning
// a helper process, who will asking the shell to elevate the process for
// a helper process, that will ask the shell to elevate the process for
// us. This might cause a UAC prompt. The elevation is performed on a
// background thread, as to not block the UI thread.
// Arguments:

View File

@@ -54,6 +54,16 @@ namespace winrt::TerminalApp::implementation
ScrollDown = 1
};
enum class ConfirmCloseDialogKind
{
Pane,
Tab,
MultiplePanes,
MultipleTabs,
Window,
CloseAll
};
struct RenameWindowRequestedArgs : RenameWindowRequestedArgsT<RenameWindowRequestedArgs>
{
WINRT_PROPERTY(winrt::hstring, ProposedName);
@@ -168,6 +178,7 @@ namespace winrt::TerminalApp::implementation
void OpenSettingsUI();
void WindowActivated(const bool activated);
bool FocusTab(const winrt::TerminalApp::Tab& tab);
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
@@ -192,6 +203,7 @@ namespace winrt::TerminalApp::implementation
til::typed_event<IInspectable, IInspectable> IdentifyWindowsRequested;
til::typed_event<IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs> RenameWindowRequested;
til::typed_event<IInspectable, IInspectable> SummonWindowRequested;
til::typed_event<IInspectable, winrt::TerminalApp::Tab> FocusTabRequested;
til::typed_event<IInspectable, winrt::Microsoft::Terminal::Control::WindowSizeChangedEventArgs> WindowSizeChanged;
til::typed_event<IInspectable, IInspectable> OpenSystemMenu;
@@ -301,8 +313,7 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowDialogHelper(const std::wstring_view& name);
void _ShowAboutDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowQuitDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCloseWarningDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowConfirmCloseDialog(ConfirmCloseDialogKind kind);
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowCloseReadOnlyDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowMultiLinePasteWarningDialog();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> _ShowLargePasteWarningDialog();
@@ -349,7 +360,7 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine _ExportTab(const Tab& tab, winrt::hstring filepath);
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::Tab tab);
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::Tab tab, bool skipConfirmClose = false);
void _CloseTabAtIndex(uint32_t index);
void _RemoveTab(const winrt::TerminalApp::Tab& tab);
safe_void_coroutine _RemoveTabs(const std::vector<winrt::TerminalApp::Tab> tabs);
@@ -400,9 +411,12 @@ namespace winrt::TerminalApp::implementation
TerminalApp::Tab _GetTabByTabViewItem(const IInspectable& tabViewItem) const noexcept;
void _HandleClosePaneRequested(std::shared_ptr<Pane> pane);
bool _ShouldWarnOnClose() const;
bool _ShouldWarnOnCloseTab(const winrt::com_ptr<Tab>& tab) const;
safe_void_coroutine _SetFocusedTab(const winrt::TerminalApp::Tab tab);
safe_void_coroutine _CloseFocusedPane();
void _ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds);
safe_void_coroutine _ClosePanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds);
void _CloseRemainingPanes(weak_ref<Tab> weakTab, std::vector<uint32_t> paneIds);
winrt::Windows::Foundation::IAsyncOperation<bool> _PaneConfirmCloseReadOnly(std::shared_ptr<Pane> pane);
void _AddPreviouslyClosedPaneOrTab(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>&& args);
@@ -412,7 +426,7 @@ namespace winrt::TerminalApp::implementation
const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
std::shared_ptr<Pane> newPane);
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
bool _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
void _ToggleSplitOrientation();
void _ScrollPage(ScrollDirection scrollDirection);
@@ -422,8 +436,9 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine _PasteFromClipboardHandler(const IInspectable sender,
const Microsoft::Terminal::Control::PasteFromClipboardEventArgs eventArgs);
void _OpenHyperlinkHandler(const IInspectable sender, const Microsoft::Terminal::Control::OpenHyperlinkEventArgs eventArgs);
bool _IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri);
safe_void_coroutine _OpenHyperlinkHandler(const IInspectable sender, const Microsoft::Terminal::Control::OpenHyperlinkEventArgs eventArgs);
static bool _IsUriSupported(const winrt::Windows::Foundation::Uri& parsedUri);
static bool _IsUriConsideredSomewhatSafe(const winrt::Windows::Foundation::Uri& parsedUri);
void _ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri);
bool _CopyText(bool dismissSelection, bool singleLine, bool withControlSequences, Microsoft::Terminal::Control::CopyFormat formats);
@@ -570,6 +585,8 @@ namespace winrt::TerminalApp::implementation
void _activePaneChanged(winrt::TerminalApp::Tab tab, Windows::Foundation::IInspectable args);
safe_void_coroutine _doHandleSuggestions(Microsoft::Terminal::Settings::Model::SuggestionsArgs realArgs);
void _SendDesktopNotification(const winrt::hstring& tabTitle, const winrt::hstring& body, const winrt::com_ptr<Tab>& tab, const winrt::TerminalApp::IPaneContent& content);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);

View File

@@ -86,17 +86,12 @@
Grid.Row="2"
x:Load="False" />
<ContentDialog x:Name="QuitDialog"
x:Uid="QuitDialog"
<ContentDialog x:Name="ConfirmCloseDialog"
Grid.Row="2"
x:Load="False"
DefaultButton="Primary" />
<ContentDialog x:Name="CloseAllDialog"
x:Uid="CloseAllDialog"
Grid.Row="2"
x:Load="False"
DefaultButton="Primary" />
DefaultButton="Primary">
<CheckBox x:Uid="DontAskAgainCheckBox" />
</ContentDialog>
<ContentDialog x:Name="CloseReadOnlyDialog"
x:Uid="CloseReadOnlyDialog"
@@ -144,17 +139,17 @@
</TextBlock>
</ContentDialog>
<ContentDialog x:Name="CouldNotOpenUriDialog"
x:Uid="CouldNotOpenUriDialog"
<ContentDialog x:Name="UriErrorDialog"
x:Uid="UriErrorDialog"
Grid.Row="2"
x:Load="False"
DefaultButton="Primary">
DefaultButton="Close">
<TextBlock IsTextSelectionEnabled="True"
TextWrapping="WrapWholeWords">
<TextBlock.ContextFlyout>
<mtu:TextMenuFlyout />
</TextBlock.ContextFlyout>
<Run x:Name="CouldNotOpenUriReason" /> <LineBreak />
<Run x:Name="CouldNotOpenUriReason" /> <LineBreak /> <LineBreak />
<Run x:Name="UnopenedUri"
FontFamily="Cascadia Mono" />
</TextBlock>

View File

@@ -102,7 +102,7 @@ namespace winrt::TerminalApp::implementation
args.Profile(::Microsoft::Console::Utils::GuidToString(_profile.Guid()));
// If we know the user's working directory use it instead of the profile.
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
if (const auto dir = _control.WorkingDirectory(); ::Microsoft::Console::Utils::IsValidDirectory(dir.c_str()))
{
args.StartingDirectory(dir);
}
@@ -291,9 +291,11 @@ namespace winrt::TerminalApp::implementation
_control.BellLightOn();
}
// raise the event with the bool value corresponding to the taskbar flag
// raise the event with the bool values corresponding to the taskbar and notification flags
BellRequested.raise(*this,
*winrt::make_self<TerminalApp::implementation::BellEventArgs>(WI_IsFlagSet(_profile.BellStyle(), BellStyle::Taskbar)));
*winrt::make_self<TerminalApp::implementation::BellEventArgs>(
WI_IsFlagSet(_profile.BellStyle(), BellStyle::Taskbar),
WI_IsFlagSet(_profile.BellStyle(), BellStyle::Notification)));
}
}
}

View File

@@ -4,6 +4,7 @@
#pragma once
#include "TerminalPaneContent.g.h"
#include "BellEventArgs.g.h"
#include "NotificationEventArgs.g.h"
#include "BasicPaneEvents.h"
namespace winrt::TerminalApp::implementation
@@ -13,10 +14,21 @@ namespace winrt::TerminalApp::implementation
struct BellEventArgs : public BellEventArgsT<BellEventArgs>
{
public:
BellEventArgs(bool flashTaskbar) :
FlashTaskbar(flashTaskbar) {}
BellEventArgs(bool flashTaskbar, bool sendNotification) :
FlashTaskbar(flashTaskbar), SendNotification(sendNotification) {}
til::property<bool> FlashTaskbar;
til::property<bool> SendNotification;
};
struct NotificationEventArgs : public NotificationEventArgsT<NotificationEventArgs>
{
public:
NotificationEventArgs(const winrt::hstring& title = {}, const winrt::hstring& body = {}) :
Title(title), Body(body) {}
til::property<winrt::hstring> Title;
til::property<winrt::hstring> Body;
};
struct TerminalPaneContent : TerminalPaneContentT<TerminalPaneContent>, BasicPaneEvents

View File

@@ -108,13 +108,19 @@ static Documents::Run _BuildErrorRun(const winrt::hstring& text, const ResourceD
Documents::Run textRun;
textRun.Text(text);
// Color the text red (light theme) or yellow (dark theme) based on the system theme
auto key = winrt::box_value(L"ErrorTextBrush");
if (resources.HasKey(key))
// GH #18147 - In High Contrast mode, don't override the foreground.
// Let the text inherit the system HC text color from its parent element,
// since SystemErrorTextColor doesn't adapt to High Contrast themes.
if (!winrt::Windows::UI::ViewManagement::AccessibilitySettings{}.HighContrast())
{
auto g = resources.Lookup(key);
auto brush = g.try_as<winrt::Windows::UI::Xaml::Media::Brush>();
textRun.Foreground(brush);
// Color the text red (light theme) or yellow (dark theme) based on the system theme
auto key = winrt::box_value(L"ErrorTextBrush");
if (resources.HasKey(key))
{
auto g = resources.Lookup(key);
auto brush = g.try_as<winrt::Windows::UI::Xaml::Media::Brush>();
textRun.Foreground(brush);
}
}
return textRun;
@@ -861,7 +867,7 @@ namespace winrt::TerminalApp::implementation
// - Used to tell the app that the titlebar has been clicked. The App won't
// actually receive any clicks in the titlebar area, so this is a helper
// to clue the app in that a click has happened. The App will use this as
// a indicator that it needs to dismiss any open flyouts.
// an indicator that it needs to dismiss any open flyouts.
// Arguments:
// - <none>
// Return Value:
@@ -1205,6 +1211,15 @@ namespace winrt::TerminalApp::implementation
}
}
bool TerminalWindow::FocusTab(const winrt::TerminalApp::Tab& tab)
{
if (_root)
{
return _root->FocusTab(tab);
}
return false;
}
void TerminalWindow::WindowName(const winrt::hstring& name)
{
const auto oldIsQuakeMode = _WindowProperties->IsQuakeWindow();

View File

@@ -92,6 +92,7 @@ namespace winrt::TerminalApp::implementation
bool ShowTabsFullscreen() const;
bool AutoHideWindow();
void IdentifyWindow();
bool FocusTab(const winrt::TerminalApp::Tab& tab);
std::optional<uint32_t> LoadPersistedLayoutIdx() const;
winrt::Microsoft::Terminal::Settings::Model::WindowLayout LoadPersistedLayout();
@@ -221,6 +222,7 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress);
FORWARDED_TYPED_EVENT(IdentifyWindowsRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IdentifyWindowsRequested);
FORWARDED_TYPED_EVENT(SummonWindowRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, SummonWindowRequested);
FORWARDED_TYPED_EVENT(FocusTabRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::Tab, _root, FocusTabRequested);
FORWARDED_TYPED_EVENT(OpenSystemMenu, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, OpenSystemMenu);
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
FORWARDED_TYPED_EVENT(ShowWindowChanged, Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs, _root, ShowWindowChanged);

Some files were not shown because too many files have changed in this diff Show More