Compare commits

..

52 Commits

Author SHA1 Message Date
Dustin L. Howett
22a7a5bc5f Migrate spelling-0.0.21 changes from main 2022-06-13 15:03:41 -07:00
Pankaj Bhojwani
b3997a3dad preview connection ctor takes preview string 2022-06-13 15:03:41 -07:00
HO-COOH
d866908eaf Fix mis-aligned Navigationview footer and save buttons in the settings page (#13282)
This improves the layout/appearance of the settings UI footer, by reducing
the height of the main content footer to match the navigation view footer.
2022-06-13 15:12:18 +00:00
Leonard Hecker
2e7a95ddb5 Fix uninitialized memory bug in GdiEngine (#13271)
ed27737 contains a regression were a `RECT` in `GdiEngine` wasn't properly
initialized anymore. Due to this, rendering during scrolling behaved erratic.

To find other cases of this bug in ed27737 the following regex was used:
```
^-.* = \{\s*\d*\s*\};
```

It appears that only `GdiEngine` was affected by a bug of this kind,
but just to be sure, this PR reverts all other instances.
This bug was likely caused when I tried to undo some of the changes in
ed27737 to make the PR smaller, but failed to revert the code properly.

## PR Checklist
* [x] Closes #13270
* [x] I work here

## Validation Steps Performed
I'm unable to reproduce the issue on my hardware and am unable to test
this change, but the uninitialized struct is clearly a bug regardless.

Co-authored-by: James Holderness <j4_james@hotmail.com>
2022-06-13 11:18:53 +00:00
Ian O'Neill
75e462441d Add an accelerator key for the shell extension (#13080)
Adds an accelerator key for the shell extension: `T` for stable, `P` for preview and `D` for dev.

# Validation
Ran a dev build and saw the keyboard accelerator assigned.

Closes #13061
2022-06-10 21:05:02 +00:00
James Holderness
c754f4d22d Restore the DECCTR color table report over conpty (#13227)
## Summary of the Pull Request

Up to now we haven't supported passing `DCS` sequences over conpty, so
any `DCS` operations would just be ignored in Windows Terminal. This PR
introduces a mechanism whereby we can selectively pass through
operations that could reasonably be handled by the connected terminal
without interfering with the regular conpty renderer. For now this is
just used to support restoring the `DECCTR` color table report.

## References

Support for `DECCTR` was originally added to conhost in PR #13139.

## PR Checklist
* [x] Closes #13223
* [x] CLA signed.
* [x] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not
checked, I'm ready to accept this work might be rejected in favor of a
different grand plan. Issue number where discussion took place: #xxx

## Detailed Description of the Pull Request / Additional comments

The way this works is we have a helper method in `AdaptDispatch` that
`DCS` operations can use to create a passthrough `StringHandler` for the
incoming data instead of their usual handler. To make this passthrough
process more efficient, the handler buffers the data before forwarding
it to conpty.

However, it's important that we aren't holding back data if output is
paused before the string terminator, so we need to flush the buffer
whenever we reach the end of the current write operation. This is
achieved by querying a new method in the `StateMachine` that lets us
know if we're currently dealing with the last character.

Another issue that came up was with the way the `StateMachine` caches
sequences that it might later need to forward to conpty. In the case of
string sequences like `DCS`, we don't want the actual string data cached
here, because that will just waste memory, and can also result in the
data being mistakenly output. So I've now disabled that caching when
we're in any of the string processing states.

## Validation Steps Performed

I've manually confirmed that the `DECCTR` sequence can now update the
color table in Windows Terminal. I've also added a new unit test in
`ConptyRoundtripTests` to verify the sequence is being passed through
successfully.
2022-06-10 19:13:17 +00:00
Mike Griese
b22684e697 Filter focus events that came from the API (#13260)
As described in #13238. libuv sends a focus event to jiggle the handle. Now that we support focus events as VT input (#12900), we'd translate those focus events to VT input as well. That combination of things caused exiting neovim to emit a `\x1b[O` to the input line of the shell when exited. 

To fix this, we're going to secretly filter out any focus events that came from the API, before translating to VT. We're fortunate here, the `FOCUS_EVENT_RECORD` version of the ctor is only called by the API. 

* [x] Closes #13238
2022-06-10 18:38:47 +00:00
Matthew Daly
1b630ab6f6 Accept color name "magenta" instead of "purple" (#13261)
When loading color schemes from Json, check if GetValueForKey failed. If
it did, and we were searching for the colors "purple"/"brightPurple",
swap out the color name with "magenta"/"brightMagenta" and try again.
This was tested manually by creating a new color scheme using the colors
"magenta"/"brightMagenta" and loading it, then printing colored text in
the terminal to assure that the colors were correctly assigned as
purple.

This changes the color loader to use an index pair table to add support
for alternate color names.

## Validation Steps Performed
- Manually edit settings.json, creating a new color scheme with colors
  "magenta" and "brightMagenta"
- View the color scheme in settings - the colors will appear as "purple"
  and "brightPurple" in the UI
- Run a program that prints colored text, purple and brightPurple text
  will appear in the colors defined as magenta and brightMagenta
- Modify the color scheme in the settings UI and save it, the colors
  will be saved as "purple" and "brightPurple" *(I think this is the
  right behavior, since calling them "magenta" is technically a
  mistake)*
- Repeat the steps above with a normal color scheme - colors named
  "purple" and "brightPurple" still load properly

Closes #11456
2022-06-10 18:37:39 +00:00
Hui Yoo
cac52a9e30 Initialize Terminal Preview settings from Terminal settings (#12907)
Windows Terminal Preview gets existing settings from Release build if
Preview settings are empty

This ensures that when settings are empty or not existent, we check if
we're currently in a preview build and if we are, we attempt to grab
settings from the Release build's setting path instead. We tested it
manually by changing settings in Release build and confirming that
changes migrated to Preview when settings are empty or not existent.
Additionally, we tested that settings.json of the running build changed.
We also ran existing TAEF testing locally and it passed.

In LoadAll() function in
src\cascadia\TerminalSettingsModel\CascadiaSettingsSerialization.cpp, we
first checked if the settings file us empty/exists via settingsString.
If it does not and we are in the Preview build, we try loading the
Release build's settings. We created modified versions of
CascadiaSettings::_settingsPath() and GetBaseSettingsPath() to get the
path for the Release build's settings. If the Release build settings do
exist and firstTimeSetup is true, we set it to settingsString so it can
be written to disk via WriteSettingsToDisk(). Note that currently we
hardcode the path of the Release build. This pull request was worked on
with @Dannihu01.

## Validation Steps Performed Test1: Setting to firstTimeSetup is true
and loading settings.json from WT release when release exists -> Result:
settings.json AND GUI reflected WT release’s settings

Test2: Setting to firstTimeSetup is true and loading settings.json from
WT release when release doesn’t exist -> Result: settings.json AND GUI
reflected DEFAULT settings

Test3: (After running Test1) Setting to firstTimeSetup is false and
seeing if current settings.json matches WT release. (See if it doesn’t
change) -> Result: settings.json AND GUI reflected WT release’s settings

Closes #6855 

Co-authored-by: Danniell Hu <dannihu@umich.edu>
2022-06-10 18:35:00 +00:00
Carlos Zamora
94e1697a48 Fix a11y crash in alt buffer apps (#13250)
## Summary of the Pull Request
This fixes the crashes caused by using a screen reader when in an app that uses the alt buffer via two changes:
1. Fix `Terminal::ViewEndIndex()`
   - `UiaTextRangeBase` receives a coordinate that is outside of the bounds of the text buffer via the following chain of functions... `_getDocumentEnd()` --> `GetLastNonSpaceCharacter()` --> `_getOptimizedBufferSize()` --> `GetTextBufferEndPoisition()` --> `ViewEndIndex()`
   - Since support for the alt buffer was added recently, `ViewEndIndex()` was recently changed, so that explains why this issue came up recently. We were accidentally setting the view end index to `height` instead of `height-1`. Thanks @j4james for finding this!
   - The UIA code would get the "exclusive end" of the alt buffer. Since it was using `ViewEndIndex()` to calculate that, it was one more than it should be. The UIA code has explicit allowance for "one past the end of the viewport" in its `IsInBounds()` check. Since the `ViewEndIndex()` is way beyond that, it's not allowed, hitting the fail fast.
2. Replace `FAIL_FAST_IF` with `assert`
   - These fail fast calls have caused so many issues with our UIA code. Those checks still provide value, but they shouldn't take the whole app down. This change replaces the `Viewport` and `UiaTextRangeBase` fail fasts with asserts to still perform those checks, but not take down the entire app in release builds.

Closes #13183 

## Validation Steps Performed
While using Narrator...
- opened nano in bash
- generated text and scrolled in nano
- generated text and scrolled in PowerShell
2022-06-10 18:09:09 +00:00
Mike Griese
1de1325cd1 Update roadmap for 1.13, 1.14. (#13234)
I threw that Gannt chart that I whipped up a few weeks ago in here, but if we feel that should be pulled because it's more a set of [guidelines than actual rules](https://c.tenor.com/aeV80XD4CSgAAAAC/guidlines-pirates-of-the-caribbean.gif), then we can pull it. 

* [x] Closes #13222
2022-06-10 18:07:53 +00:00
Mike Griese
dc8183a525 Add "JSON" to the "Open settings file" command names (#13265)
![image](https://user-images.githubusercontent.com/18356694/173090336-3512ee36-ae8b-41d5-8823-09cb1354c7ef.png)

* [x] Closes #13225
2022-06-10 16:41:13 +00:00
Mike Griese
2a7dd8b730 Make sure foreground access works for DefTerm (#13247)
See also: #12799, the origin of much of this.

This change evolved over multiple phases. 

### Part the first

When we create a defterm connection in `TerminalPage::_OnNewConnection`,
we don't have the hosting HWND yet, so the tab gets created without one.
We'll later get called with the owner, in `Initialize`. 

To remedy this, we need to:
* In `Initialize`, make sure to update any existing controls with the
  new owner.
* In `ControlCore`, actually propogate the new owner down to the
  connection

### Part the second

DefTerm launches don't actually request focus mode, so the Terminal
never sends them focus events. We need those focus events so that the
console can request foreground rights.

To remedy this, we need to:
* pass `--win32input` to the commandline used to initialize OpenConsole
  in ConPTY mode. We request focus events at the same time we request
  win32-input-mode.
* I also added `--resizeQuirk`, because _by all accounts that should be
  there_. Resizing in defterm windows should be _wacky_ without it, and
  I'm a little surprised we haven't seen any bugs due to this yet.

### Part the third

`ConsoleSetForeground` expects a `HANDLE` to the process we want to give
foreground rights to. The problem is, the wire format we used _also_
decided that a HANDLE value was a good idea. It's not. If we pass the
literal value of the HANDLE to the process from OpenConsole to conhost,
so conhost can call that API, the value that conhost uses there will
most likely be an invalid handle. The HANDLE's value is its value in
_OpenConsole_, not in conhost.

To remedy this, we need to:
* Just not forward `ConsoleSetForeground`. Turns out, we _can_ just call
  that in OpenConsole safely. There's no validation. So just instantiate
  a static version of the Win32 version of ConsoleControl, just to use
  for SetForeground. (thanks Dustin)

* [x] Tested manually - Win+R `powershell`, `notepad` spawns on top.

Closes #13211
2022-06-09 23:12:26 +00:00
Mike Griese
f685720cac Implement the FTCS_PROMPT sequence for marking the start of the prompt (#13163)
Implements the **FTCS_PROMPT** sequence, `OSC 133 ; A ST`. In this PR, it's just used to set a simple Prompt mark on the current line, in the same way that the iTerm2 sequence works.

There's rumination in #11000 on how to implement the rest of the FTCS sequences. 

This is broken into its own PR at the moment. [Quoth j4james](https://github.com/microsoft/terminal/pull/12948#issuecomment-1136360132):

> That should be just as easy, and I've noticed a couple of other terminals that are doing that, so it's not unprecedented. If we don't have any immediate use for the other options, there shouldn't be any harm in ignoring them initially.
> 
> And the benefit of going with the more widely supported sequence is that we're more likely to benefit from any shells that have this functionality built in. Otherwise they're forced to try and detect the terminal, which is practically impossible for Windows Terminal. Even iTerm2 supports the `OSC 133` sequence, so we'd probably be the only odd one out.

This part of the plumbing is super easy, so I thought it would be valuable to add regardless if we get to the whole of FTCS in 1.15.

* [x] I work here
* [x] Tested manually - in my pwsh `$PROFILE`:
  ```pwsh
  function prompt {
    $loc = $($executionContext.SessionState.Path.CurrentLocation);
    $out = "PS $loc$('>' * ($nestedPromptLevel + 1)) ";
    $out += "$([char]27)]9;9;`"$loc`"$([char]07)";
    $out += "$([char]27)]133;A;$([char]7)"; # add the FTCS_PROMPT to the... well, end, but you get the point
    return $out
  }
  ```
* See also #11000
2022-06-09 22:42:44 +00:00
Dustin L. Howett
205c09ccb8 Hide the use of MIDI behind velocity (#13258)
* conhost requires an additional dependency in Windows, which might
  cause us trouble in WPG
* Terminal requires an additional *package* dependency, which *will*
  cause us trouble in WPG (since GmDls is about 3MB)

I chose to scope the feature checks to MidiOut directly, as I wanted to
keep the delay behavior in MidiAudio::PlayNote. This is negotiable.

References #13252
2022-06-09 17:40:15 -05:00
Mike Griese
799b5d4add Experimental: add support for scrollbar marks (#12948)
Adds support for marks in the scrollbar. These marks can be added in 3
ways:
* Via the iterm2 `OSC 1337 ; SetMark` sequence
* Via the `addMark` action
* Automatically when the `experimental.autoMarkPrompts` per-profile
  setting is enabled.

#11000 has more tracking for the big-picture for this feature, as well
as additional follow-ups. This set of functionality seemed complete
enough to send a review for now. That issue describes these how I wish
these actions to look in the fullness of time.  This is simply the v0.1
from the hackathon last month.

#### Actions

* `addMark`: add a mark to the buffer. If there's a selection, use
   place the mark covering at the selection. Otherwise, place the mark
   on the cursor row. 
  - `color`: a color for the scrollbar mark. This is optional - defaults
    to the `foreground` color of the current scheme if omitted.
* `scrollToMark`
  - `direction`: `["first", "previous", "next", "last"]`
* `clearMark`: Clears marks at the current postition (either the
  selection if there is one, or the cursor position.
* `clearAllMarks`: Don't think this needs explanation.

#### Per-profile settings

* `experimental.autoMarkPrompts`: `bool`, default `false`.
* `experimental.showMarksOnScrollbar`: `bool` 

## PR Checklist
* [x] Closes #1527
* [x] Closes #6232

## Detailed Description of the Pull Request / Additional comments

This is basically hackathon code. It's experimental! That's okay! We'll
figure the rest of the design in post.

Theoretically, I should make these actions `experimental.` as well, but
it seemed like since the only way to see these guys was via the
`experimental.showMarksOnScrollbar` setting, you've already broken
yourself into experimental jail, and you know what you're doing.

Things that won't work as expected:
* resizing, ESPECIALLY reflowing
* Clearing the buffer with ED sequences / Clear Buffer

I could theoretically add velocity around this in the `TermControl`
layer. Always prevent marks from being visible, ignore all the actions.
Marks could still be set by VT and automark, but they'd be useless.

Next up priorities:
* Making this work with the FinalTerm sequences
* properly speccing
* adding support for `showMarksOnScrollbar: flags(categories)`, so you
  can only display errors on the scrollbar
* adding the `category` flag to the `addMark` action

## Validation Steps Performed

I like using it quite a bit. The marks can get noisy if you have them
emitted on every prompt and the buffer has 9000 lines. But that's the
beautiful thing, the actions work even if the marks aren't visible, so
you can still scroll between prompts. 

<details>
<summary>Settings blob</summary>

```jsonc
// actions
        { "keys": "ctrl+up", "command": { "action": "scrollToMark", "direction": "previous" }, "name": "Previous mark" },
        { "keys": "ctrl+down", "command": { "action": "scrollToMark", "direction": "next" }, "name": "Next mark" },
        { "keys": "ctrl+pgup", "command": { "action": "scrollToMark", "direction": "first" }, "name": "First mark" },
        { "keys": "ctrl+pgdn", "command": { "action": "scrollToMark", "direction": "last" }, "name": "Last mark" },
        { "command": { "action": "addMark" } },
        { "command": { "action": "addMark", "color": "#ff00ff" } },
        { "command": { "action": "addMark", "color": "#0000ff" } },
        { "command": { "action": "clearAllMarks" } },

// profiles.defaults
        "experimental.autoMarkPrompts": true,
        "experimental.showMarksOnScrollbar": true,
```

</details>
2022-06-09 16:10:16 -05:00
Leonard Hecker
730eb5fafd Fix signed/unsigned arithmetic bug during scrolling (#13256)
ed27737 contains a regression where (pseudocode)
```c
unsigned long ulActualDelta;
short ScreenInfo.WheelDelta;
delta *= (ScreenInfo.WheelDelta / (short)ulActualDelta);
//                                ^^^^^^^
```
was changed to
```c
delta *= (ScreenInfo.WheelDelta / ulActualDelta);
```

Due to `ulActualDelta` being unsigned, the new code casts the signed integer
to a unsigned one first, before doing the division. This causes scrolling
downwards (`WheelDelta` is negative) to appear as a large positive `delta`.

## PR Checklist
* [x] Closes #13253
* [x] I work here

## Validation Steps Performed
* Scrolling up/down works in OpenConsole again 
2022-06-09 19:55:04 +00:00
Dustin L. Howett
cd35bc5989 Restore OpenConsoleProxyStub's dependency on the CRT to fix QI (#13254)
When #13160 introduced a new interface to the IConsoleHandoff idl, it
changed midl's RPC proxy stub lookup algorithm from a direct GUID
comparison to an unrolled binary search. Now, that would ordinarily not
be a problem...

However, in #11610, we took a shortcut and replaced `memcmp` -- used
only by RPC for GUID comparison -- with a direct GUID-only equality
comparator. This worked totally fine, and ordinarily would not be a
problem...

The unrolled binary search unfortunately _relies on memcmp's contract_:
it uses memcmp to match against a fully sorted set. Our memcmp only
returned 0 or 1 (equal or not), and it knew nothing about ordering.

When a package that contains a PackagedCOM proxy stub is installed, it
is selected as the primary proxy stub for any interfaces it can proxy.
After all, interfaces are immutable, so it doesn't matter whose proxy
you're using. Now, given that we installed a *broken* proxy... *all*
IIDs that got whacked by our memcmp issue broke for every consumer.

To fix it: instead of implementing memcmp ourselves, we're just going to
take a page out of WinAppSDK's book and link this binary using the
"Hybrid CRT" model. It will statically link any parts of the STL it uses
(none) and dynamically link the ucrt (which is guaranteed to be present
on Windows.)

Sure, the binary size goes up from 8k to 24k, but... the cost is never
having to worry about this again.

Closes #13251
2022-06-09 19:48:28 +00:00
PankajBhojwani
4e20a8631c Fix deleting the last profile crashing Terminal (#13242)
## Summary of the Pull Request
When a profile gets deleted, we were navigating to the next item assuming it was a profile when it may not be. This commit fixes this by checking the tag of the next menu item before we navigate to it. 

## PR Checklist
* [x] Closes #13125 
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I work here

## Validation Steps Performed
Deleting the last profile in the SUI doesn't cause a crash
2022-06-08 02:46:43 +00:00
Leonard Hecker
1b81c6540f Use feature markers during terminal-by-default handoff (#13160)
If we want to make Windows Terminal the default terminal under Windows,
we'll have to make conhost "handoff" incoming connections by default.
But this poses a problem: How can the seldomly updated conhost know
whether the routinely updated Windows Terminal version is actually willing
to accept such handoffs by default (it might be unwilling due to bugs, etc.)?

This commit solves the issue by introducing:
* A marker interface (`IDefaultTerminalMarker`): If it exists,
  Windows Terminal indicates its willingness to accept the handoff.
* Turning the all-0 GUID from being synonymous for conhost,
  to being synonymous for "Let Windows decide". Without this we wouldn't
  be able to differentiate between users who consciously chose conhost
  as their default terminal, vs. users who want the standard behavior.

## Validation Steps Performed
Testing fallback behavior:
* Install "Terminal" 1.13
* Delete the 2 keys below `HKCU\Console\%%Startup`
* Enable `Feature_AttemptHandoff` in `features.xml`
  Return `true` from `DefaultApp::CheckShouldTerminalBeDefault`
* Replace `conhost.exe` and `console.dll` with `sfpcopy` after building
* Launching `cmd.exe` launches as a conhost window 
  (because "Terminal" 1.13 lacks the marker interface)
* Open properties page in `conhost.exe`
  "Let Windows decide" is select by default 
* Changing the selection writes the new value 

Testing the new behavior:
* Delete the 2 keys below `HKCU\Console\%%Startup`
* Enable `Feature_AttemptHandoff` in `features.xml`
  Return `true` from `DefaultApp::CheckShouldTerminalBeDefault`
* Use `CLSID_WindowsTerminalConsoleDev` and `CLSID_WindowsTerminalTerminalDev`
  for the initialization of `TerminalDelegationPair`
* Replace `conhost.exe` and `console.dll` with `sfpcopy` after building
* Deploy the "Terminal Dev" package
* Launching `cmd.exe` launches "Terminal Dev" 
  (because "Terminal Dev" has the marker interface)
* Open the settings tab
  "Let Windows decide" is select by default 
* Changing the selection and saving writes the new value 
2022-06-07 19:31:02 +00:00
PankajBhojwani
f4c4efc7f0 Reorder "save" and "discard changes" buttons in the SUI (#13237)
"Save" is now the first button, "Discard changes" is now the second button

## PR Checklist
* [x] Closes #13174
2022-06-07 10:56:04 +00:00
Carlos Zamora
d76c70c470 Introduce toggleBlockSelection action (#13219)
## Summary of the Pull Request
This introduced the `toggleBlockSelection` action to allow users to create a block selection using only the keyboard. This is not bound to any keys by default, however it is added to the command palette.

## References
#4993 - Epic
#5804 - Spec

## Validation Steps Performed
- [X] Mark mode always starts in line selection mode
- [X] Mouse selections are always in line selection mode by default
- [X] Can toggle block selection for an existing selection (regardless of how it was created)
- [X] The selection is copied properly (aka, no rendering issues)
2022-06-07 10:55:17 +00:00
Leonard Hecker
ed27737233 Use 32-bit coordinates throughout the project (#13025)
Previously this project used a great variety of types to present text buffer
coordinates: `short`, `unsigned short`, `int`, `unsigned int`, `size_t`,
`ptrdiff_t`, `COORD`/`SMALL_RECT` (aka `short`), and more.
This massive commit migrates almost all use of those types over to the
centralized types `til::point`/`size`/`rect`/`inclusive_rect` and their
underlying type `til::CoordType` (aka `int32_t`).

Due to the size of the changeset and statistics I expect it to contain bugs.
The biggest risk I see is that some code potentially, maybe implicitly, expected
arithmetic to be mod 2^16 and that this code now allows it to be mod 2^32.
Any narrowing into `short` later on would then throw exceptions.

## PR Checklist
* [x] Closes #4015
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
Casual usage of OpenConsole and Windows Terminal. 
2022-06-03 23:02:46 +00:00
James Holderness
c157f6346a Add support for restoring a DECCTR color table report (#13139)
This PR introduces the framework for the `DECRSTS` sequence which is
used to restore terminal state reports. But to start with, I've just
implemented the `DECCTR` color table report, which provides a way for
applications to alter the terminal's color scheme.

## PR Checklist
* [x] Closes #13132
* [x] CLA signed.
* [x] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Detailed Description of the Pull Request / Additional comments

I've added the functions for parsing DEC RGB and HLS color formats into
the `Utils` class, where we've got all our other color parsing routines,
since this functionality will eventually be needed in other VT protocols
like Sixel and ReGIS.

Since `DECRSTS` is a `DCS` sequence, this only works in conhost for now,
or when using the experimental passthrough mode in Windows Terminal.

## Validation Steps Performed

I've added a number of unit tests to check that the `DECCTR` report is
being interpreted as expected. This includes various edge cases (e.g.
omitted and out-of-range parameters), which I have confirmed to match
the color parsing on a real VT240 terminal.
2022-06-03 01:52:00 +00:00
James Holderness
9dca6c27ee Add support for the DECPS (Play Sound) escape sequence (#13208)
## Summary of the Pull Request

The `DECPS` (Play Sound) escape sequence provides applications with a
way to play a basic sequence of musical notes. This emulates
functionality that was originally supported on the DEC VT520 and VT525
hardware terminals.

## PR Checklist
* [x] Closes #8687
* [x] CLA signed.
* [ ] Tests added/passed
* [ ] Documentation updated.
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. Issue number
where discussion took place: #8687

## Detailed Description of the Pull Request / Additional comments

When a `DECPS` control is executed, any further output is blocked until
all the notes have finished playing. So to prevent the UI from hanging
during this period, we have to temporarily release the console/terminal
lock, and then reacquire it before returning.

The problem we then have is how to deal with the terminal being closed
during that unlocked interval. The way I've dealt with that is with a
promise that is set to indicate a shutdown. This immediately aborts any
sound that is in progress, but also signals the thread that it needs to
exit as soon as possible.

The thread exit is achieved by throwing a custom exception which is
recognised by the state machine and rethrown instead of being logged.
This gets it all the way up to the root of the write operation, so it
won't attempt to process anything further output that might still be
buffered.

## Validation Steps Performed

Thanks to the testing done by @jerch on a real VT525 terminal, we have a
good idea of how this sequence is supposed to work, and I'm fairly
confident that our implementation is reasonably compatible.

The only significant difference I'm aware of is that we support multiple
notes in a sequence. That was a feature that was documented in the
VT520/VT525 manual, but didn't appear to be supported on the actual
device.
2022-06-01 17:53:56 +00:00
Leonard Hecker
7dbe741e1a Fix SetConsoleWindowInfo being able to crash ConPTY (#13212)
MSFT-33471786 is one of the most common crashes we have right now.
Memory dumps suggest that `VtEngine::UpdateViewport` is called with a rectangle
like `(0, 46, 119, 29)` (left, top, right, bottom), which is a rectangle of
negative height. When the `_invalidMap` is resized the negative size gets
turned into a very large unsigned integer, which results in an OOM exception,
crashing OpenConsole.

`VtEngine::UpdateViewport` is called by `Renderer::_CheckViewportAndScroll`
which holds a (cached) old and a new viewport. The old viewport was
`(0, 46, 119, 75)` which is exceedingly similar to the invalid, new viewport.
It's bottom coordinate is also coincidentally larger by exactly 46 (top).

The viewport comes from the `SCREEN_INFORMATION` class whose `SetViewport`
function was highly suspicious as it has a branch which updates the bottom
to be the buffer height, but leaves the top unmodified.

`SCREEN_INFORMATION::SetViewport` is called by `SetConsoleWindowInfo` which
processes user-provided data. A repro of the crash can be constructed with:
```
SMALL_RECT rect{0, 46, 119, 75};
SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect);
```

Closes #13193
Closes MSFT-33471786

## Validation Steps Performed
Ensured the following code doesn't crash when run under Windows Terminal:
```
SMALL_RECT rect{0, 46, 119, 75};
SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect);
```
2022-06-01 17:47:22 +00:00
leejy12
fb1491a4af Hide "Open in Terminal" context menu option appropriately (#13206)
This commit hides the "Open in Terminal" context menu option when the
context menu is opened in a non-filesystem path like "Quick Actions".

Closes #12578
2022-05-31 17:47:52 +00:00
Mike Griese
11b810e403 Prevent ConPTY from de-snapping the terminal (#13164)
This is a big hammer to put out this fire. We're keeping the hiding around for now, cause we think that's likely the one that the internal tests use that we really care about here. If we need to bring this back, we can. 

* [x] Closes #13158
* [x] Closes #13162
* [x] Validated these both manually 
* [x] `[Native]::ShowWindow([Native]::GetConsoleWindow(), 6)` still works
2022-05-25 15:01:36 -05:00
Ian O'Neill
6439b4d807 Don't attempt to split settings tabs (#13172)
Prevents a null pointer dereference when attempting to split a settings tab, due to it not being a terminal tab.

* [x] Closes #13166

## Validation Steps Performed
Manually tested.
2022-05-25 19:58:04 +00:00
Dustin L. Howett
78852e04ec Remove location-specific suffixes from the zh- lang specifiers (#13148)
This only impacts the UI. We can take a workitem to rename the loc data
later. When the user specifies zh-Hans/zh-Hant, the resource mapper does
the right thing.

Related to #8984
2022-05-24 16:57:54 +00:00
Mike Griese
c5fad74c54 Debounce window state changes caused by the PTY (#13147)
Use a throttled update to update our window state. Throttling should prevent scenarios where the Terminal window state and PTY window state get de-sync'd, and cause the window to minimize/restore constantly in a loop.  "Should" is doing a lot of work in this sentence. 

A 200ms delay was chosen because it's the typical animation timeout in Windows. This does result in a delay between the PTY requesting a change to the window state and the Terminal realizing it, but should mitigate issues where the Terminal and PTY get desync'd.


I think we're overall not super confident that this fixes the root causes of the issue. Rather, we're hopeful that a small amount of throttling here should leave time for the Terminal and pty to sync back up. We're comfortable enough with that as a bandaid for 1.14 preview, to see how this behaves in the wild.
2022-05-23 23:04:26 +00:00
Mike Griese
bb03b00ebf Fix the SUI being in the wrong Theme color (#13145)
ThemeResources are a persistent pain.

Regressed in #13083. See also #12775 et. al.

We can't just put those here though as StaticResources, because XAML will evaluate their values when the App is first loaded, and we'll always use the value from the OS theme, regarless of the requested theme. Kinda the same thing we've had to do with TabViewBackground in the past.

* [x] Fixes something we noticed right before shipping
2022-05-23 18:01:13 +00:00
Mike Griese
4c333536b4 Add the background back to showTabsInTitlebar: false's tab row. (#13144)
We're doing it this way because ThemeResources are tricky. We
default in XAML to using the appropriate ThemeResource background
color for our TabRow. When tabs in the titlebar are _disabled_,
this will ensure that the tab row has the correct theme-dependent
value. When tabs in the titlebar are _enabled_ (the default),
we'll switch the BG to Transparent, to let the Titlebar Control's
background be used as the BG for the tab row.

We can't do it the other way around (default to Transparent, only
switch to a color when disabling tabs in the titlebar), because
looking up the correct ThemeResource from and App dictionary is a
capital-H Hard problem.

* [x] Closes #13143
* [x] I work here
* [x] validated manually:
  - [x] showTabsInTitlebar: false, true
  - [x] useAcrylicInTabRow: false, true
  - [x] theme: light, dark
* [x] Need to check if this is regressed the same in 1.13. I suspect it is.
2022-05-23 16:16:57 +00:00
Carlos Zamora
bf41a90ad8 Introduce Mark Mode (#13053)
## Summary of the Pull Request
Introduces a non-configurable version of mark mode to Windows Terminal. It has the following interactions defined:
- <kbd>ctrl+shift+m</kbd> --> Enter Mark Mode
- when in Mark Mode...
	- <kbd>ESC</kbd> --> Exit Mark Mode
	- arrow keys --> move "start"
	- <kbd>shift</kbd> + arrow keys --> anchor "start", move "end"
	- <kbd>ctrl+a</kbd> --> select all
- when a selection is active...

When in mark mode, the cursor does not blink.

## References
#4993 - [Epic] Keyboard Selection

## PR Checklist
* [X] Closes #715
* [X] Provides a resolution for #11985

## Detailed Description of the Pull Request / Additional comments
- `TermControl`:
	- `TermControl.cpp` just adds logic to prevent the cursor from blinking when in mark mode
- `ControlCore`
	- in the same place we handle quick edit, we add an entry point to mark mode
- `TerminalCore`
	- this leverages `UpdateSelection()` and other quick edit functions to make mark mode happen

## Validation Steps Performed
- [x] Make selection, split pane, close pane
	- NOTE: A similar scenario caused a crash at one point. Really weird. Keep an eye on it.
- [x] Cursor is off when in mark mode
- [x] general movement/selection
- [x] general movement/selection that forces the viewport to move
- [x] In mark mode, selectAll...
	- [x] arrow keys --> move start
	- [x] shift + arrow keys --> move end
- [x] (regardless of mark mode) if selection active, enter --> copy to clipboard
2022-05-20 23:04:53 +00:00
Mike Griese
d82af9367f Fis ShowHide for DefTerm (#13129)
Well this one feels dumb.

Make sure to also initially set the visibility of ConPTY windows created for DefTerm connections.

* [x] Closes #13066 for real.
* [x] tested manually.
2022-05-19 15:11:52 -05:00
Mike Griese
77215d9d77 Fix ShowWindow(GetConsoleWindow()) (#13118)
A bad merge, that actually revealed a horrible bug.

There was a secret conflict between the code in #12526 and #12515. 69b77ca was a bad merge that hid just how bad the issue was. Fixing the one line `nullptr`->`this` in `InteractivityFactory` resulted in a window that would flash uncontrollably, as it minimized and restored itself in a loop. Great. 

This can seemingly be fixed by making sure that the conpty window is initially created with the owner already set, rather than relying on a `SetParent` call in post. This does pose some complications for the #1256 future we're approaching. However, this is a blocking bug _now_, and we can figure out the tearout/`SetParent` thing in post. 

* fixes #13066.
* Tested with the script in that issue.
* Window doesn't flash uncontrollably.
* `gci | ogv` still works right
* I work here.
* Opening a new tab doesn't spontaneously cause the window to minimize
* Restoring from minimized doesn't yeet focus to an invisible window
* Opening a new tab doesn't yeet focus to an invisible window
* There _is_ a viable way to call `GetAncestor` s.t. it returns the Terminal's hwnd in Terminal, and the console's in Conhost


The `SW_SHOWNOACTIVATE` change is also quite load bearing. With just `SW_NORMAL`, the pseudo window (which is invisible!) gets activated whenever the terminal window is restored from minimized. That's BAD.


There's actually more to this as well. 


Calling `SetParent` on a window that is `WS_VISIBLE` will cause the OS to hide the window, make it a _child_ window, then call `SW_SHOW` on the window to re-show it. `SW_SHOW`, however, will cause the OS to also set that window as the _foreground_ window, which would result in the pty's hwnd stealing the foreground away from the owning terminal window. That's bad.

`SetWindowLongPtr` seems to do the job of changing who the window owner is, without all the other side effects of reparenting the window. 

Without `SetParent`, however, the pty HWND is no longer a descendant of the Terminal HWND, so that means `GA_ROOT` can no longer be used to find the owner's hwnd. For even more insanity, without `WS_POPUP`, none of the values of `GetAncestor` will actually get the terminal HWND. So, now we also need `WS_POPUP` on the pty hwnd. To get at the Terminal hwnd, you'll need

```c++
GetAncestor(GetConsoleWindow(), GA_ROOTOWNER)
```
2022-05-18 17:25:06 -05:00
James Holderness
0154da5d33 Add support for line renditions in the DX renderer (#13102)
This PR adds support for the VT line rendition attributes in the DirectX
renderer, which allows for double-width and double-height line
renditions.

Line renditions were first implemented in conhost (with the GDI
renderer) in PR #8664.  Supporting them in the DX renderer now is a
small step towards #11595.

The DX implementation is very similar to the GDI one. When a particular
line rendition is requested, we create a transform that is applied to
the render target. And in the case of double-height renditions, we also
initialize some clipping offsets to allow for the fact that we only
render half of a line at a time.

One additional complication exists when drawing the cursor, which
requires a two part process where it first renders to a command list,
and then draw the command list in a second step. We need to temporarily
reset the transform in that first stage otherwise it ends up being
applied twice.

I've manually tested the renderer in conhost by setting the `UseDx`
registry entry and confirmed that it passes the _Vttest_ double-size
tests as well as several of my own tests. I've also checked that the
renderer can now handle horizontal scrolling, which is a feature we get
for free with the transforms.
2022-05-18 18:17:06 +00:00
James Holderness
e1086de512 Fix handling of cursor position reports in passthrough mode (#13109)
## Summary of the Pull Request

When the conpty passthrough mode is enabled, it often needs to send `DSR-CPR` queries (cursor position reports) to the client terminal to obtain the current cursor position. However, the code that originally handled the responses to these queries got broken by the refactoring of the `ConGetSet` API. This PR is an attempt to correct that regression.

## References

The conpty passthrough mode was introduced in PR #11264.
The refactoring that broke the cursor position handling was in PR #12703.

## PR Checklist
* [x] Closes #13106
* [x] CLA signed.
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Detailed Description of the Pull Request / Additional comments

Prior to the `ConGetSet` refactoring, the code that handled `DSR-CPR` responses (`InteractDispatch::MoveCursor`) would pass the cursor position to `ConGetSet::SetCursorPosition`, which in turn would forward it to the `SetConsoleCursorPositionImpl` API, and from there to the `VtIo` class.

After the refactor, all of those intermediate steps were removed - the cursor was simply updated directly in `InteractDispatch::MoveCursor`, and the `VtIo` call was moved from `SetConsoleCursorPositionImpl` to `InteractDispatch` (since that was the only place it was actually required).

However, when the conpty passthrough mode was introduced - which happened in parallel - it relied on the `SetConsoleCursorPositionImpl` API being called from `InteractDispatch` in order to handle its own `DSR-CPR` responses, and that's why things stopped working when the two PRs merged.

So what I've done now is made `InteractDispatch::MoveCursor` method call `SetConsoleCursorPositionImpl` again (although without the intermediate `ConGetSet` overhead), and moved the `VtIo::SetCursorPosition` call back into `SetConsoleCursorPositionImpl`.

This is not ideal, and there are still a bunch of problems with the `DSR-CPR` handling in passthrough mode, but it's at least as good as it was before.

## Validation Steps Performed

I've just manually tested various shells with passthrough mode enabled, and confirmed that they're working better now. There are still issues, but nothing that wasn't already a problem in the initial implementation, at least as far as I can tell.
2022-05-17 14:56:04 +00:00
Leonard Hecker
fa6b066747 AtlasEngine: Stop resizing buffers on scroll (#13100)
This regressed in ad2358d.
We're interested in the size of the viewport only, but it can shift up/down
during scrolling. In these situations we shouldn't resize our buffers of course.

## Validation Steps Performed
* Scroll
* Not setting `ApiInvalidations::Size` 
2022-05-17 00:07:48 +00:00
Carlos Zamora
b699f9275f Add experimental.useBackgroundImageForWindow to schema (#13114)
Adds the `experimental.useBackgroundImageForWindow` global setting introduced in #12893 to the schema.
2022-05-16 19:06:05 -05:00
Sergey Semushin
b851b0d3f4 Add find item to tab menu (#13055)
## Summary of the Pull Request

Add `Find` to tab context menu as describe in issue #5633.

## PR Checklist
* [x] Closes #5633
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA

## Detailed Description of the Pull Request / Additional comments

Just wanted to solve `Easy Starter` issue, so any corrections/suggestions welcome. There's a couple of points I'm not sure of
* Placement of item within menu, currently it's at the end before close tab block.
* Should it be named longer, something like `Find in Tab` of just `Find` is fine?
* The workaround for focus similar to tab rename is a bit annoying, especially because it required adding a method to `TermControl` but without it find window obviously opens without focus which is bad.

## Validation Steps Performed

Open menu, press menu item try to find things via opened find dialog.
2022-05-16 23:30:05 +00:00
Leonard Hecker
df627c26f1 Various improvements for til::hash/point/size/rect (#13093)
This commit includes various minor improvements to til::hash/point/size/rect
which accumulated while working on #4015.

* Allow xvalue containers and non-`size_t` indices in `til::at`.
* `til::as_unsigned` can be used to reinterpret a potentially signed integer
  as a unsigned one. This can potentially enable some optimizations as no sign
  extension is needed anymore. `til::hash` can make use of this to drop about
  20% of the hashing of signed integers <= 32 bit. On x86 this translates to
  a `mov` (virtually no latency) or no instructions at all, instead of
  requiring a `movsx` (some latency) for sign extension.
* `til::point` operators that prefer mutability.
  This is a opinionated change, but it follows the STL style beter and
  generates less assembly.
* Simpler `rect` scale_up/down and `size` divide_ceil.
  `scale_up` will not depend on the operator header anymore.
  `scale_down` / `divide_ceil` can be implemented without checked numerics,
  so I did. It also follows the related GdiEngine code better now, which
  makes me confident that we can replace GdiEngine's code with this.
* Removal of rect-size-shift operators.
  They were only used in DxEngine and confusing as they weren't commutative.
  Adding and then subtracting a size from a rect (and vice versa) didn't do
  what you'd intuitively think it'd do. The code was replaced with addition
  and clamps in DxEngine.
* Various unsafe `as_` casts for point/size/rect.
  This will aid the migration in #4015.

## Validation Steps Performed
* Vertical scrolling works in `DxEngine` 
2022-05-16 23:28:32 +00:00
Leonard Hecker
1db47ff8dc Simplify Utf16Parser (#13096)
This trivial commit simplifies `Utf16Parser::IsLeading/TrailingSurrogate`
methods, by replacing `<bitset>` with a simple, equivalent range check.
2022-05-16 22:18:13 +00:00
Leonard Hecker
003cbe7c29 Reduce integer type casts in VtEngine (#13097)
This commit is one of the more difficult rewrites that were necessary as part
of #4015, but still simple enough that it can be done as a separate commit.
The search for the `lastNonSpace` was replaced with a simpler
`std::string_view::find_last_not_of`.

## Validation Steps Performed
ConPTY appears to work 
2022-05-16 22:16:57 +00:00
Carlos Zamora
6ffc3dc7a8 Revert "Hide the window from DWM until we're finished with initialization (#12979)" (#13098)
This reverts commit 14098d71f2.

## Summary of the Pull Request
@zadjii-msft found that this is causing persisted windows on a secondary monitor to shrink a little each time. We're choosing to revert this commit until that gets resolved.

## References
#12979
2022-05-13 13:30:18 -05:00
Leonard Hecker
1cb58a6a02 Fix various unit/feature test bugs (#13092)
This commit fixes various bugs in our unit/feature test suite:
* 2 tests failed at 150% scale.
* The "null key" (@ on a US keyboard) isn't necessarily Shift+2.
  The proper way to get it is with `LOBYTE(VkKeyScanW(0))`
* `InputEngineTest::C0Test` never worked as it overwrote
  the loop variable, exiting the loop early
2022-05-13 18:29:01 +00:00
Leonard Hecker
0630b18eff Fix various issues with useBackgroundImageForWindow (#13090)
Fixes the following issues:
* `desktopWallpaper` not working
* switching tabs/panes causes the background to flicker
* settings preview having a transparent background

## PR Checklist
* [x] Closes #13002
* [x] I work here
* [x] Tests added/passed

## Validation Steps Performed
Tested the 3 cases above. 
2022-05-12 22:49:13 +00:00
Carlos Zamora
17d1e2437c Fix the 'RunMakeKillTabs' PGO test (#13089)
## Summary of the Pull Request
For some reason, the PGO tests (specifically the `RunMakeKillTabs` test) started to fail after #12979 merged. After closer inspection, the test was actually improperly written. We should be using <kbd>ctrl+shift+t</kbd> to open new tabs, not <kbd>alt+shift+t</kbd>. Presumably, the <kbd>alt</kbd> was copied over from the previous test, because they look _very_ similar.

So I went ahead and fixed the test, and it now (1) tests what it's intended to test and (2) doesn't fail. Why did #12979 cause the tests to fail? idk, but it works now.

## References
#10071 - Introduce PGO Tests

## Validation Steps Performed
Ran PGO tests locally and confirmed that it works.
Ran PGO pipeline and confirmed that it works.
2022-05-12 20:38:26 +00:00
James Holderness
c2f830843a Restore virtual viewport position after resize with reflow (#13087)
When the buffer is resized with a reflow, we were previously calculating
the new virtual bottom based on the position of last non-space
character. If the viewport was largely blank when resized, this could
result in the new virtual bottom being higher than it should be.

This PR attempts to address that problem by restoring the virtual bottom
to a position that is the same distance from the cursor row as it was
prior to the resize.

This was a regression introduced in PR #12972.

We still take the last non-space row into account when determining the
virtual bottom, because if the content of the screen is forced to wrap,
the virtual bottom will need to be lower (relative to the cursor) than
it was before.

We also need to check that we don't overflow the bottom of the buffer,
which can occur when the viewport is at the bottom of the buffer, and
the cursor position is pushed down as a result of content wrapping above
it.

I've manually confirmed that this fixes the problem reported in issue
#13078, and I've also extended the existing `RefreshWithReflow` unit
test to cover that particular scenario.

Closes #13078
2022-05-12 20:26:35 +00:00
Ofer Zelig
1d3e1568a2 Fix some typos in mouseInput.cpp (#13085) 2022-05-12 20:20:06 +00:00
James Holderness
a69ce89712 Add support for the DECAC escape sequence (#13058)
The `DECAC` (Assign Colors) escape sequence controls which color table
entries are associated with the default foreground and background
colors. This is how you would change the default colors on the the
original DEC VT525 terminals.

But `DECAC` also allows you to assign the color table entries for the
"window frame", which in our case is mapped to the tab color (just the
background for now). So this now gives us a way to control the tab color
via an escape sequence as well.

DETAILS
-------

The way this works is there are now two new entries in the color table
for the frame colors, and two new aliases in the color alias table that
are mapped to those color table entries. As previously mentioned, only
the background is used for now.

By default, the colors are set to `INVALID_COLOR`, which indicates that
the system colors should be used. But if the user has set a `tabColor`
property in their profile, the frame background will be initialized with
that value instead.

And note that some of the existing color table entries are now
renumbered for compatibility with XTerm, which uses entries 256 to 260
for special colors which we don't yet support. Our default colors are
now at 261 and 262, the frame colors are 263 and 264, and the cursor
color is 265. 

So at runtime, you can change the tab color programmatically by setting
the color table entry at index 262 using `OSC 4` (assuming you need a
specific RGB value). Otherwise if you just want to set the tab color to
an existing color index, you can use `DECAC 2`.

You can even make the tab color automatically match background color by
mapping the frame background alias to the color table entry for the
default background, using `DECAC 2;261;262` (technically this is mapping
both the the foreground and background).

This PR doesn't include support for querying the color mapping with
`DECRQSS`, and doesn't support resetting the colors with `RIS`, but
hopefully those can be figured out in a future PR - there are some
complications that'll need to be resolved first.

## Validation Steps Performed

I've added a basic unit test that confirms the `DECAC` escape sequence
updates the color aliases in the render settings as expected. I've also
manually confirmed that the tab color in Windows Terminal is updated by
`DECAC 2`, and the default colors are updated in both conhost and WT
using `DECAC 1`.

Closes #6574
2022-05-12 20:18:40 +00:00
Carlos Zamora
9cb2bccd7f version: bump to 1.15 on main 2022-05-11 11:55:33 -07:00
363 changed files with 7179 additions and 5513 deletions

View File

@@ -410,6 +410,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InteractivityOneCore", "src
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererWddmCon", "src\renderer\wddmcon\lib\wddmcon.vcxproj", "{75C6F576-18E9-4566-978A-F0A301CAC090}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Audio", "Audio", "{40BD8415-DD93-4200-8D82-498DDDC08CC8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MidiAudio", "src\audio\midi\lib\midi.vcxproj", "{3C67784E-1453-49C2-9660-483E2CC7F7AD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
AuditMode|Any CPU = AuditMode|Any CPU
@@ -3449,6 +3453,46 @@ Global
{75C6F576-18E9-4566-978A-F0A301CAC090}.Release|x64.Build.0 = Release|x64
{75C6F576-18E9-4566-978A-F0A301CAC090}.Release|x86.ActiveCfg = Release|Win32
{75C6F576-18E9-4566-978A-F0A301CAC090}.Release|x86.Build.0 = Release|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|x64.ActiveCfg = AuditMode|x64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|x64.Build.0 = AuditMode|x64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|x86.ActiveCfg = AuditMode|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.AuditMode|x86.Build.0 = AuditMode|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|Any CPU.ActiveCfg = Debug|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|ARM.ActiveCfg = Debug|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|ARM64.ActiveCfg = Debug|ARM64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|ARM64.Build.0 = Debug|ARM64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|x64.ActiveCfg = Debug|x64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|x64.Build.0 = Debug|x64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|x86.ActiveCfg = Debug|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Debug|x86.Build.0 = Debug|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|x64.Build.0 = Fuzzing|x64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Fuzzing|x86.Build.0 = Fuzzing|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|Any CPU.ActiveCfg = Release|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|ARM.ActiveCfg = Release|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|ARM64.ActiveCfg = Release|ARM64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|ARM64.Build.0 = Release|ARM64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|x64.ActiveCfg = Release|x64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|x64.Build.0 = Release|x64
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|x86.ActiveCfg = Release|Win32
{3C67784E-1453-49C2-9660-483E2CC7F7AD}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -3552,6 +3596,8 @@ Global
{8222900C-8B6C-452A-91AC-BE95DB04B95F} = {05500DEF-2294-41E3-AF9A-24E580B82836}
{06EC74CB-9A12-428C-B551-8537EC964726} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
{75C6F576-18E9-4566-978A-F0A301CAC090} = {05500DEF-2294-41E3-AF9A-24E580B82836}
{40BD8415-DD93-4200-8D82-498DDDC08CC8} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
{3C67784E-1453-49C2-9660-483E2CC7F7AD} = {40BD8415-DD93-4200-8D82-498DDDC08CC8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}

View File

@@ -111,10 +111,10 @@ repository.
---
## Windows Terminal 2.0 Roadmap
## Windows Terminal Roadmap
The plan for delivering Windows Terminal 2.0 [is described
here](/doc/terminal-v2-roadmap.md) and will be updated as the project proceeds.
The plan for the Windows Terminal [is described here](/doc/roadmap-2022.md) and
will be updated as the project proceeds.
## Project Build Status

View File

@@ -4,5 +4,5 @@
<package id="Microsoft.Taef" version="10.60.210621002" targetFramework="native" />
<package id="Microsoft.Internal.PGO-Helpers.Cpp" version="0.2.34" targetFramework="native" />
<!-- This cannot be included in another project that depends on XAML (as it would be a duplicate package ID) -->
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.7.0" targetFramework="native" />
</packages>

View File

@@ -9,7 +9,7 @@
<PropertyGroup>
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
<PGOBranch>release-1.14</PGOBranch>
<PGOBranch>main</PGOBranch>
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>

View File

@@ -30,7 +30,7 @@ jobs:
If ($Arch -Eq "x86") { $Arch = "Win32" }
Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
- template: restore-nuget-steps.yml
- steps: restore-nuget-steps.yml
- task: UniversalPackages@0
displayName: Download terminal-internal Universal Package
inputs:

View File

@@ -18,14 +18,14 @@
This version should be tracked in all project packages.config files for projects that depend on Xaml.
-->
<TerminalMUXVersion>2.7.3-prerelease.220816001</TerminalMUXVersion>
<TerminalMUXVersion>2.7.2-prerelease.220406002</TerminalMUXVersion>
<!--
For the Windows 11-specific build, we're targeting the public version of Microsoft.UI.Xaml.
This version emits a package dependency instead of embedding the dependency in our own package.
This version should be tracked in build/packages.config.
-->
<TerminalMUXVersion Condition="'$(TerminalTargetWindowsVersion)'=='Win11'">2.7.3</TerminalMUXVersion>
<TerminalMUXVersion Condition="'$(TerminalTargetWindowsVersion)'=='Win11'">2.7.1</TerminalMUXVersion>
</PropertyGroup>
</Project>

View File

@@ -17,7 +17,7 @@
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
<XesBaseYearForStoreVersion>2022</XesBaseYearForStoreVersion>
<VersionMajor>1</VersionMajor>
<VersionMinor>14</VersionMinor>
<VersionMinor>15</VersionMinor>
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
</PropertyGroup>
</Project>

View File

@@ -10,13 +10,13 @@
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
<package id="Microsoft.Internal.Windows.Terminal.ThemeHelpers" version="0.6.220404001" targetFramework="native" />
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
<package id="Microsoft.UI.Xaml" version="2.7.3-prerelease.220816001" targetFramework="native" />
<package id="Microsoft.UI.Xaml" version="2.7.2-prerelease.220406002" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.220201.1" targetFramework="native" developmentDependency="true" />
<!-- Managed packages -->
<package id="Appium.WebDriver" version="3.0.0.2" targetFramework="net45" />
<package id="Castle.Core" version="4.1.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net45" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net45" />
<package id="Selenium.Support" version="3.5.0" targetFramework="net45" />
<package id="Selenium.WebDriver" version="3.5.0" targetFramework="net45" />
</packages>

View File

@@ -318,6 +318,7 @@
"moveFocus",
"movePane",
"swapPane",
"markMode",
"moveTab",
"multipleActions",
"newTab",
@@ -2010,10 +2011,6 @@
"description": "Controls what happens when the application emits a BEL character. When set to \"all\", the Terminal will play a sound, flash the taskbar icon (if the terminal window is not in focus) and flash the window. An array of specific behaviors can also be used. Supported array values include `audible`, `window` and `taskbar`. When set to \"none\", nothing will happen.",
"$ref": "#/$defs/BellStyle"
},
"bellSound": {
"description": "Sets the sound played when the application emits a BEL. When set to an array, the terminal will pick one of those sounds at random.",
"$ref": "#/$defs/BellSound"
},
"closeOnExit": {
"default": "graceful",
"description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.",

View File

@@ -22,21 +22,61 @@ Below is the schedule for when milestones will be included in release builds of
| Milestone End Date | Milestone Name | Preview Release Blog Post |
| ------------------ | -------------- | ------------------------- |
| 2020-06-18 | [1.1] in Windows Terminal Preview | [Windows Terminal Preview 1.1 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-1-release/) |
| 2020-07-31 | [1.2] in Windows Terminal Preview<br>[1.1] in Windows Terminal | [Windows Terminal Preview 1.2 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-2-release/) |
| 2020-08-31 | [1.3] in Windows Terminal Preview<br>[1.2] in Windows Terminal | [Windows Terminal Preview 1.3 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-3-release/) |
| 2020-09-30 | [1.4] in Windows Terminal Preview<br>[1.3] in Windows Terminal | [Windows Terminal Preview 1.4 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-4-release/) |
| 2020-11-30 | [1.5] in Windows Terminal Preview<br>[1.4] in Windows Terminal | [Windows Terminal Preview 1.5 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-5-release/) |
| 2021-01-31 | [1.6] in Windows Terminal Preview<br>[1.5] in Windows Terminal | [Windows Terminal Preview 1.6 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-6-release/) |
| 2021-03-01 | [1.7] in Windows Terminal Preview<br>[1.6] in Windows Terminal | [Windows Terminal Preview 1.7 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-7-release/) |
| 2021-04-14 | [1.8] in Windows Terminal Preview<br>[1.7] in Windows Terminal | [Windows Terminal Preview 1.8 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-8-release/) |
| 2021-05-31 | [1.9] in Windows Terminal Preview<br>[1.8] in Windows Terminal | [Windows Terminal Preview 1.9 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-9-release/) |
| 2021-07-14 | [1.10] in Windows Terminal Preview<br>[1.9] in Windows Terminal | [Windows Terminal Preview 1.10 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-10-release/) |
| 2021-08-31 | [1.11] in Windows Terminal Preview<br>[1.10] in Windows Terminal | [Windows Terminal Preview 1.11 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-11-release/) |
| 2021-10-20 | [1.12] in Windows Terminal Preview<br>[1.11] in Windows Terminal | [Windows Terminal Preview 1.12 Release](https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-12-release/) |
| | [1.13] in Windows Terminal Preview<br>[1.12] in Windows Terminal | |
| | [1.14] in Windows Terminal Preview<br>[1.13] in Windows Terminal | |
| 2020-07-31 | [1.2] in Windows Terminal Preview<br>[1.1] in Windows Terminal | [Windows Terminal Preview 1.2 Release] |
| 2020-08-31 | [1.3] in Windows Terminal Preview<br>[1.2] in Windows Terminal | [Windows Terminal Preview 1.3 Release] |
| 2020-09-30 | [1.4] in Windows Terminal Preview<br>[1.3] in Windows Terminal | [Windows Terminal Preview 1.4 Release] |
| 2020-11-30 | [1.5] in Windows Terminal Preview<br>[1.4] in Windows Terminal | [Windows Terminal Preview 1.5 Release] |
| 2021-01-31 | [1.6] in Windows Terminal Preview<br>[1.5] in Windows Terminal | [Windows Terminal Preview 1.6 Release] |
| 2021-03-01 | [1.7] in Windows Terminal Preview<br>[1.6] in Windows Terminal | [Windows Terminal Preview 1.7 Release] |
| 2021-04-14 | [1.8] in Windows Terminal Preview<br>[1.7] in Windows Terminal | [Windows Terminal Preview 1.8 Release] |
| 2021-05-31 | [1.9] in Windows Terminal Preview<br>[1.8] in Windows Terminal | [Windows Terminal Preview 1.9 Release] |
| 2021-07-14 | [1.10] in Windows Terminal Preview<br>[1.9] in Windows Terminal | [Windows Terminal Preview 1.10 Release] |
| 2021-08-31 | [1.11] in Windows Terminal Preview<br>[1.10] in Windows Terminal | [Windows Terminal Preview 1.11 Release] |
| 2021-10-20 | [1.12] in Windows Terminal Preview<br>[1.11] in Windows Terminal | [Windows Terminal Preview 1.12 Release] |
| 2022-02-03 | [1.13] in Windows Terminal Preview<br>[1.12] in Windows Terminal | [Windows Terminal Preview 1.13 Release] |
| 2022-05-24 | [1.14] in Windows Terminal Preview<br>[1.13] in Windows Terminal | [Windows Terminal Preview 1.14 Release] |
| | [1.15] in Windows Terminal Preview<br>[1.14] in Windows Terminal | |
| | [1.16] in Windows Terminal Preview<br>[1.15] in Windows Terminal | |
| | [1.17] in Windows Terminal Preview<br>[1.16] in Windows Terminal | |
### Release outline
Below is a VERY vague outline of the remaining calendar year that was drafted late May 2022. This was drafted for internal planning purposes, as a guide. It is not meant to represent official dates. More often than not, releases are synced to official features landing, rather than arbitrary dates. Drift from this initial draft is entirely expected.
```mermaid
gantt
title Proposed Terminal Releases 1.14-1.18
dateFormat YYYY-MM-DD
axisFormat %d %b
section Terminal 1.14
Lock down & bake :done, 2022-05-06, 2w
Release 1.14 :milestone, 2022-05-24
section Terminal 1.15
Features :done, a1, 2022-05-06, 4w
Bugfix :active, a2, after a1 , 1w
Lock down & bake :after a2 , 1w
Release 1.15 :milestone, 2022-06-21, 0
1.15 becomes Stable :milestone, after b3, 0
section Terminal 1.16
Features :b1, after a2, 4w
Bugfix :b2, after b1 , 2w
Lock down & bake :b3, after b2 , 2w
Release 1.16 :milestone, after b3, 0
1.16 becomes Stable :milestone, after c3, 0
section Terminal 1.17
Features :c1, after b2, 4w
Bugfix :c2, after c1 , 2w
Lock down & bake :c3, after c2 , 2w
Release 1.17 :milestone, after c3, 0
1.17 becomes Stable :milestone, after d3, 0
section Terminal 1.18
Features :d1, after c2, 4w
Bugfix :d2, after d1 , 2w
Lock down & bake :d3, after d2 , 2w
Release 1.18 :milestone, after d3, 0
```
## Issue Triage & Prioritization
Incoming issues/asks/etc. are triaged several times a week, labeled appropriately, and assigned to a milestone in priority order:
@@ -62,7 +102,9 @@ Incoming issues/asks/etc. are triaged several times a week, labeled appropriatel
[1.12]: https://github.com/microsoft/terminal/milestone/38
[1.13]: https://github.com/microsoft/terminal/milestone/39
[1.14]: https://github.com/microsoft/terminal/milestone/41
[1.15]: https://github.com/microsoft/terminal/milestone/47
[1.16]: https://github.com/microsoft/terminal/milestone/48
[1.17]: https://github.com/microsoft/terminal/milestone/49
[22H1]: https://github.com/microsoft/terminal/milestone/43
[22H2]: https://github.com/microsoft/terminal/milestone/44
@@ -70,3 +112,17 @@ Incoming issues/asks/etc. are triaged several times a week, labeled appropriatel
[Backlog]: https://github.com/microsoft/terminal/milestone/45
[Terminal v2 Roadmap]: https://github.com/microsoft/terminal/tree/main/doc/terminal-v2-roadmap.md
[Windows Terminal Preview 1.2 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-2-release/
[Windows Terminal Preview 1.3 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-3-release/
[Windows Terminal Preview 1.4 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-4-release/
[Windows Terminal Preview 1.5 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-5-release/
[Windows Terminal Preview 1.6 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-6-release/
[Windows Terminal Preview 1.7 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-7-release/
[Windows Terminal Preview 1.8 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-8-release/
[Windows Terminal Preview 1.9 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-9-release/
[Windows Terminal Preview 1.10 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-10-release/
[Windows Terminal Preview 1.11 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-11-release/
[Windows Terminal Preview 1.12 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-12-release/
[Windows Terminal Preview 1.13 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-13-release/
[Windows Terminal Preview 1.14 Release]: https://devblogs.microsoft.com/commandline/windows-terminal-preview-1-14-release/

View File

@@ -0,0 +1,125 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "MidiAudio.hpp"
#include "../terminal/parser/stateMachine.hpp"
namespace
{
class MidiOut
{
public:
static constexpr auto NOTE_OFF = 0x80;
static constexpr auto NOTE_ON = 0x90;
static constexpr auto PROGRAM_CHANGE = 0xC0;
// We're using a square wave as an approximation of the sound that the
// original VT525 terminals might have produced. This is probably not
// quite right, but it works reasonably well.
static constexpr auto SQUARE_WAVE_SYNTH = 80;
MidiOut() noexcept
{
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
{
midiOutOpen(&handle, MIDI_MAPPER, NULL, NULL, CALLBACK_NULL);
OutputMessage(PROGRAM_CHANGE, SQUARE_WAVE_SYNTH);
}
}
~MidiOut() noexcept
{
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
{
midiOutClose(handle);
}
}
void OutputMessage(const int b1, const int b2, const int b3 = 0, const int b4 = 0) noexcept
{
if constexpr (Feature_DECPSViaMidiPlayer::IsEnabled())
{
midiOutShortMsg(handle, MAKELONG(MAKEWORD(b1, b2), MAKEWORD(b3, b4)));
}
}
MidiOut(const MidiOut&) = delete;
MidiOut(MidiOut&&) = delete;
MidiOut& operator=(const MidiOut&) = delete;
MidiOut& operator=(MidiOut&&) = delete;
private:
HMIDIOUT handle = nullptr;
};
}
using namespace std::chrono_literals;
MidiAudio::~MidiAudio() noexcept
{
try
{
#pragma warning(suppress : 26447)
// We acquire the lock here so the class isn't destroyed while in use.
// If this throws, we'll catch it, so the C26447 warning is bogus.
_inUseMutex.lock();
}
catch (...)
{
// If the lock fails, we'll just have to live with the consequences.
}
}
void MidiAudio::Initialize()
{
_shutdownFuture = _shutdownPromise.get_future();
}
void MidiAudio::Shutdown()
{
// Once the shutdown promise is set, any note that is playing will stop
// immediately, and the Unlock call will exit the thread ASAP.
_shutdownPromise.set_value();
}
void MidiAudio::Lock()
{
_inUseMutex.lock();
}
void MidiAudio::Unlock()
{
// We need to check the shutdown status before releasing the mutex,
// because after that the class could be destroyed.
const auto shutdownStatus = _shutdownFuture.wait_for(0s);
_inUseMutex.unlock();
// If the wait didn't timeout, that means the shutdown promise was set,
// so we need to exit the thread ASAP by throwing an exception.
if (shutdownStatus != std::future_status::timeout)
{
throw Microsoft::Console::VirtualTerminal::StateMachine::ShutdownException{};
}
}
void MidiAudio::PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept
try
{
// The MidiOut is a local static because we can only have one instance,
// and we only want to construct it when it's actually needed.
static MidiOut midiOut;
if (velocity)
{
midiOut.OutputMessage(MidiOut::NOTE_ON, noteNumber, velocity);
}
// By waiting on the shutdown future with the duration of the note, we'll
// either be paused for the appropriate amount of time, or we'll break out
// of the wait early if we've been shutdown.
_shutdownFuture.wait_for(duration);
if (velocity)
{
midiOut.OutputMessage(MidiOut::NOTE_OFF, noteNumber, velocity);
}
}
CATCH_LOG()

View File

@@ -0,0 +1,36 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- MidiAudio.hpp
Abstract:
This modules provide basic MIDI support with blocking sound output.
*/
#pragma once
#include <future>
#include <mutex>
class MidiAudio
{
public:
MidiAudio() = default;
MidiAudio(const MidiAudio&) = delete;
MidiAudio(MidiAudio&&) = delete;
MidiAudio& operator=(const MidiAudio&) = delete;
MidiAudio& operator=(MidiAudio&&) = delete;
~MidiAudio() noexcept;
void Initialize();
void Shutdown();
void Lock();
void Unlock();
void PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept;
private:
std::promise<void> _shutdownPromise;
std::future<void> _shutdownFuture;
std::mutex _inUseMutex;
};

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{3c67784e-1453-49c2-9660-483e2cc7f7ad}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>midi</RootNamespace>
<ProjectName>MidiAudio</ProjectName>
<TargetName>MidiAudio</TargetName>
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<Import Project="$(SolutionDir)src\common.build.pre.props" />
<Import Project="$(SolutionDir)src\common.nugetversions.props" />
<ItemGroup>
<ClCompile Include="..\MidiAudio.cpp" />
<ClCompile Include="..\precomp.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\MidiAudio.hpp" />
<ClInclude Include="..\precomp.h" />
</ItemGroup>
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
<Import Project="$(SolutionDir)src\common.build.post.props" />
<Import Project="$(SolutionDir)src\common.nugetversions.targets" />
</Project>

View File

@@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"

30
src/audio/midi/precomp.h Normal file
View File

@@ -0,0 +1,30 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- precomp.h
Abstract:
- Contains external headers to include in the precompile phase of console build process.
- Avoid including internal project headers. Instead include them only in the classes that need them (helps with test project building).
--*/
#pragma once
// clang-format off
// This includes support libraries from the CRT, STL, WIL, and GSL
#include "LibraryIncludes.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMCX
#define NOHELP
#define NOCOMM
#endif
// Windows Header Files:
#include <windows.h>
// clang-format on

View File

@@ -11,8 +11,8 @@
// - attr - the default text attribute
// Return Value:
// - constructed object
ATTR_ROW::ATTR_ROW(const uint16_t width, const TextAttribute attr) :
_data(width, attr) {}
ATTR_ROW::ATTR_ROW(const til::CoordType width, const TextAttribute attr) :
_data(gsl::narrow_cast<uint16_t>(width), attr) {}
// Routine Description:
// - Sets all properties of the ATTR_ROW to default values
@@ -32,9 +32,9 @@ void ATTR_ROW::Reset(const TextAttribute attr)
// - newWidth - The new width of the row.
// Return Value:
// - <none>, throws exceptions on failures.
void ATTR_ROW::Resize(const uint16_t newWidth)
void ATTR_ROW::Resize(const til::CoordType newWidth)
{
_data.resize_trailing_extent(newWidth);
_data.resize_trailing_extent(gsl::narrow<uint16_t>(newWidth));
}
// Routine Description:
@@ -45,9 +45,9 @@ void ATTR_ROW::Resize(const uint16_t newWidth)
// - the text attribute at column
// Note:
// - will throw on error
TextAttribute ATTR_ROW::GetAttrByColumn(const uint16_t column) const
TextAttribute ATTR_ROW::GetAttrByColumn(const til::CoordType column) const
{
return _data.at(column);
return _data.at(gsl::narrow<uint16_t>(column));
}
// Routine Description:
@@ -74,7 +74,7 @@ std::vector<uint16_t> ATTR_ROW::GetHyperlinks() const
// - attr - Attribute (color) to fill remaining characters with
// Return Value:
// - <none>
bool ATTR_ROW::SetAttrToEnd(const uint16_t beginIndex, const TextAttribute attr)
bool ATTR_ROW::SetAttrToEnd(const til::CoordType beginIndex, const TextAttribute attr)
{
_data.replace(gsl::narrow<uint16_t>(beginIndex), _data.size(), attr);
return true;
@@ -103,9 +103,9 @@ void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAtt
// - newAttr: The attribute to merge into this row.
// Return Value:
// - <none>
void ATTR_ROW::Replace(const uint16_t beginIndex, const uint16_t endIndex, const TextAttribute& newAttr)
void ATTR_ROW::Replace(const til::CoordType beginIndex, const til::CoordType endIndex, const TextAttribute& newAttr)
{
_data.replace(beginIndex, endIndex, newAttr);
_data.replace(gsl::narrow<uint16_t>(beginIndex), gsl::narrow<uint16_t>(endIndex), newAttr);
}
ATTR_ROW::const_iterator ATTR_ROW::begin() const noexcept

View File

@@ -30,7 +30,7 @@ class ATTR_ROW final
public:
using const_iterator = rle_vector::const_iterator;
ATTR_ROW(uint16_t width, TextAttribute attr);
ATTR_ROW(til::CoordType width, TextAttribute attr);
~ATTR_ROW() = default;
@@ -40,13 +40,13 @@ public:
noexcept = default;
ATTR_ROW& operator=(ATTR_ROW&&) noexcept = default;
TextAttribute GetAttrByColumn(uint16_t column) const;
TextAttribute GetAttrByColumn(til::CoordType column) const;
std::vector<uint16_t> GetHyperlinks() const;
bool SetAttrToEnd(uint16_t beginIndex, TextAttribute attr);
bool SetAttrToEnd(til::CoordType beginIndex, TextAttribute attr);
void ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAttribute& replaceWith);
void Resize(uint16_t newWidth);
void Replace(uint16_t beginIndex, uint16_t endIndex, const TextAttribute& newAttr);
void Resize(til::CoordType newWidth);
void Replace(til::CoordType beginIndex, til::CoordType endIndex, const TextAttribute& newAttr);
const_iterator begin() const noexcept;
const_iterator end() const noexcept;

View File

@@ -17,7 +17,7 @@
// Note: will through if unable to allocate char/attribute buffers
#pragma warning(push)
#pragma warning(disable : 26447) // small_vector's constructor says it can throw but it should not given how we use it. This suppresses this error for the AuditMode build.
CharRow::CharRow(size_t rowWidth, ROW* const pParent) noexcept :
CharRow::CharRow(til::CoordType rowWidth, ROW* const pParent) noexcept :
_data(rowWidth, value_type()),
_pParent{ FAIL_FAST_IF_NULL(pParent) }
{
@@ -30,9 +30,9 @@ CharRow::CharRow(size_t rowWidth, ROW* const pParent) noexcept :
// - <none>
// Return Value:
// - the size of the row
size_t CharRow::size() const noexcept
til::CoordType CharRow::size() const noexcept
{
return _data.size();
return gsl::narrow_cast<til::CoordType>(_data.size());
}
// Routine Description:
@@ -55,7 +55,7 @@ void CharRow::Reset() noexcept
// - newSize - the new width of the character and attributes rows
// Return Value:
// - S_OK on success, otherwise relevant error code
[[nodiscard]] HRESULT CharRow::Resize(const size_t newSize) noexcept
[[nodiscard]] HRESULT CharRow::Resize(const til::CoordType newSize) noexcept
{
try
{
@@ -93,14 +93,14 @@ typename CharRow::const_iterator CharRow::cend() const noexcept
// - <none>
// Return Value:
// - The calculated left boundary of the internal string.
size_t CharRow::MeasureLeft() const noexcept
til::CoordType CharRow::MeasureLeft() const noexcept
{
auto it = _data.cbegin();
while (it != _data.cend() && it->IsSpace())
{
++it;
}
return it - _data.cbegin();
return gsl::narrow_cast<til::CoordType>(it - _data.cbegin());
}
// Routine Description:
@@ -109,17 +109,17 @@ size_t CharRow::MeasureLeft() const noexcept
// - <none>
// Return Value:
// - The calculated right boundary of the internal string.
size_t CharRow::MeasureRight() const
til::CoordType CharRow::MeasureRight() const
{
auto it = _data.crbegin();
while (it != _data.crend() && it->IsSpace())
{
++it;
}
return _data.crend() - it;
return gsl::narrow_cast<til::CoordType>(_data.crend() - it);
}
void CharRow::ClearCell(const size_t column)
void CharRow::ClearCell(const til::CoordType column)
{
_data.at(column).Reset();
}
@@ -149,7 +149,7 @@ bool CharRow::ContainsText() const noexcept
// Return Value:
// - the attribute
// Note: will throw exception if column is out of bounds
const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
const DbcsAttribute& CharRow::DbcsAttrAt(const til::CoordType column) const
{
return _data.at(column).DbcsAttr();
}
@@ -161,7 +161,7 @@ const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
// Return Value:
// - the attribute
// Note: will throw exception if column is out of bounds
DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
DbcsAttribute& CharRow::DbcsAttrAt(const til::CoordType column)
{
return _data.at(column).DbcsAttr();
}
@@ -173,7 +173,7 @@ DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
// Return Value:
// - <none>
// Note: will throw exception if column is out of bounds
void CharRow::ClearGlyph(const size_t column)
void CharRow::ClearGlyph(const til::CoordType column)
{
_data.at(column).EraseChars();
}
@@ -185,9 +185,9 @@ void CharRow::ClearGlyph(const size_t column)
// Return Value:
// - text data at column
// - Note: will throw exception if column is out of bounds
const CharRow::reference CharRow::GlyphAt(const size_t column) const
const CharRow::reference CharRow::GlyphAt(const til::CoordType column) const
{
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
THROW_HR_IF(E_INVALIDARG, column < 0 || column >= gsl::narrow_cast<til::CoordType>(_data.size()));
return { const_cast<CharRow&>(*this), column };
}
@@ -198,9 +198,9 @@ const CharRow::reference CharRow::GlyphAt(const size_t column) const
// Return Value:
// - text data at column
// - Note: will throw exception if column is out of bounds
CharRow::reference CharRow::GlyphAt(const size_t column)
CharRow::reference CharRow::GlyphAt(const til::CoordType column)
{
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
THROW_HR_IF(E_INVALIDARG, column < 0 || column >= gsl::narrow_cast<til::CoordType>(_data.size()));
return { *this, column };
}
@@ -209,7 +209,7 @@ std::wstring CharRow::GetText() const
std::wstring wstr;
wstr.reserve(_data.size());
for (size_t i = 0; i < _data.size(); ++i)
for (til::CoordType i = 0; i < gsl::narrow_cast<til::CoordType>(_data.size()); ++i)
{
const auto glyph = GlyphAt(i);
if (!DbcsAttrAt(i).IsTrailing())
@@ -231,9 +231,9 @@ std::wstring CharRow::GetText() const
// - wordDelimiters: the delimiters defined as a part of the DelimiterClass::DelimiterChar
// Return Value:
// - the delimiter class for the given char
const DelimiterClass CharRow::DelimiterClassAt(const size_t column, const std::wstring_view wordDelimiters) const
const DelimiterClass CharRow::DelimiterClassAt(const til::CoordType column, const std::wstring_view wordDelimiters) const
{
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
THROW_HR_IF(E_INVALIDARG, column < 0 || column >= gsl::narrow_cast<til::CoordType>(_data.size()));
const auto glyph = *GlyphAt(column).begin();
if (glyph <= UNICODE_SPACE)
@@ -265,10 +265,10 @@ const UnicodeStorage& CharRow::GetUnicodeStorage() const noexcept
// Arguments:
// - column - the column to generate the key for
// Return Value:
// - the COORD key for data access from UnicodeStorage for the column
COORD CharRow::GetStorageKey(const size_t column) const noexcept
// - the til::point key for data access from UnicodeStorage for the column
til::point CharRow::GetStorageKey(const til::CoordType column) const noexcept
{
return { gsl::narrow<SHORT>(column), _pParent->GetId() };
return { column, _pParent->GetId() };
}
// Routine Description:

View File

@@ -54,22 +54,22 @@ public:
using const_reverse_iterator = typename boost::container::small_vector_base<value_type>::const_reverse_iterator;
using reference = typename CharRowCellReference;
CharRow(size_t rowWidth, ROW* const pParent) noexcept;
CharRow(til::CoordType rowWidth, ROW* const pParent) noexcept;
size_t size() const noexcept;
[[nodiscard]] HRESULT Resize(const size_t newSize) noexcept;
size_t MeasureLeft() const noexcept;
size_t MeasureRight() const;
til::CoordType size() const noexcept;
[[nodiscard]] HRESULT Resize(const til::CoordType newSize) noexcept;
til::CoordType MeasureLeft() const noexcept;
til::CoordType MeasureRight() const;
bool ContainsText() const noexcept;
const DbcsAttribute& DbcsAttrAt(const size_t column) const;
DbcsAttribute& DbcsAttrAt(const size_t column);
void ClearGlyph(const size_t column);
const DbcsAttribute& DbcsAttrAt(const til::CoordType column) const;
DbcsAttribute& DbcsAttrAt(const til::CoordType column);
void ClearGlyph(const til::CoordType column);
const DelimiterClass DelimiterClassAt(const size_t column, const std::wstring_view wordDelimiters) const;
const DelimiterClass DelimiterClassAt(const til::CoordType column, const std::wstring_view wordDelimiters) const;
// working with glyphs
const reference GlyphAt(const size_t column) const;
reference GlyphAt(const size_t column);
const reference GlyphAt(const til::CoordType column) const;
reference GlyphAt(const til::CoordType column);
// iterators
iterator begin() noexcept;
@@ -82,7 +82,7 @@ public:
UnicodeStorage& GetUnicodeStorage() noexcept;
const UnicodeStorage& GetUnicodeStorage() const noexcept;
COORD GetStorageKey(const size_t column) const noexcept;
til::point GetStorageKey(const til::CoordType column) const noexcept;
void UpdateParent(ROW* const pParent);
@@ -91,7 +91,7 @@ public:
private:
void Reset() noexcept;
void ClearCell(const size_t column);
void ClearCell(const til::CoordType column);
std::wstring GetText() const;
protected:

View File

@@ -25,7 +25,7 @@ class CharRowCellReference final
public:
using const_iterator = const wchar_t*;
CharRowCellReference(CharRow& parent, const size_t index) noexcept :
CharRowCellReference(CharRow& parent, const til::CoordType index) noexcept :
_parent{ parent },
_index{ index }
{
@@ -51,7 +51,7 @@ private:
// what char row the object belongs to
CharRow& _parent;
// the index of the cell in the parent char row
const size_t _index;
til::CoordType _index;
CharRowCell& _cellData();
const CharRowCell& _cellData() const;

View File

@@ -21,16 +21,16 @@ enum class LineRendition
DoubleHeightBottom
};
constexpr SMALL_RECT ScreenToBufferLine(const SMALL_RECT& line, const LineRendition lineRendition)
constexpr til::inclusive_rect ScreenToBufferLine(const til::inclusive_rect& line, const LineRendition lineRendition)
{
// Use shift right to quickly divide the Left and Right by 2 for double width lines.
const SHORT scale = lineRendition == LineRendition::SingleWidth ? 0 : 1;
const auto scale = lineRendition == LineRendition::SingleWidth ? 0 : 1;
return { line.Left >> scale, line.Top, line.Right >> scale, line.Bottom };
}
constexpr SMALL_RECT BufferToScreenLine(const SMALL_RECT& line, const LineRendition lineRendition)
constexpr til::inclusive_rect BufferToScreenLine(const til::inclusive_rect& line, const LineRendition lineRendition)
{
// Use shift left to quickly multiply the Left and Right by 2 for double width lines.
const SHORT scale = lineRendition == LineRendition::SingleWidth ? 0 : 1;
const auto scale = lineRendition == LineRendition::SingleWidth ? 0 : 1;
return { line.Left << scale, line.Top, (line.Right << scale) + scale, line.Bottom };
}

View File

@@ -531,16 +531,16 @@ OutputCellView OutputCellIterator::s_GenerateView(const OutputCell& cell)
// - Gets the distance between two iterators relative to the input data given in.
// Return Value:
// - The number of items of the input run consumed between these two iterators.
ptrdiff_t OutputCellIterator::GetInputDistance(OutputCellIterator other) const noexcept
til::CoordType OutputCellIterator::GetInputDistance(OutputCellIterator other) const noexcept
{
return _pos - other._pos;
return gsl::narrow_cast<til::CoordType>(_pos - other._pos);
}
// Routine Description:
// - Gets the distance between two iterators relative to the number of cells inserted.
// Return Value:
// - The number of cells in the backing buffer filled between these two iterators.
ptrdiff_t OutputCellIterator::GetCellDistance(OutputCellIterator other) const noexcept
til::CoordType OutputCellIterator::GetCellDistance(OutputCellIterator other) const noexcept
{
return _distance - other._distance;
return gsl::narrow_cast<til::CoordType>(_distance - other._distance);
}

View File

@@ -29,7 +29,7 @@ class OutputCellIterator final
public:
using iterator_category = std::input_iterator_tag;
using value_type = OutputCellView;
using difference_type = ptrdiff_t;
using difference_type = til::CoordType;
using pointer = OutputCellView*;
using reference = OutputCellView&;
@@ -48,9 +48,9 @@ public:
operator bool() const noexcept;
ptrdiff_t GetCellDistance(OutputCellIterator other) const noexcept;
ptrdiff_t GetInputDistance(OutputCellIterator other) const noexcept;
friend ptrdiff_t operator-(OutputCellIterator one, OutputCellIterator two) = delete;
til::CoordType GetCellDistance(OutputCellIterator other) const noexcept;
til::CoordType GetInputDistance(OutputCellIterator other) const noexcept;
friend til::CoordType operator-(OutputCellIterator one, OutputCellIterator two) = delete;
OutputCellIterator& operator++();
OutputCellIterator operator++(int);

View File

@@ -21,14 +21,11 @@ OutputCellRect::OutputCellRect() noexcept :
// Arguments:
// - rows - Rows in the rectangle (height)
// - cols - Columns in the rectangle (width)
OutputCellRect::OutputCellRect(const size_t rows, const size_t cols) :
OutputCellRect::OutputCellRect(const til::CoordType rows, const til::CoordType cols) :
_rows(rows),
_cols(cols)
{
size_t totalCells;
THROW_IF_FAILED(SizeTMult(rows, cols, &totalCells));
_storage.resize(totalCells);
_storage.resize(gsl::narrow<size_t>(rows * cols));
}
// Routine Description:
@@ -37,7 +34,7 @@ OutputCellRect::OutputCellRect(const size_t rows, const size_t cols) :
// - row - The Y position or row index in the buffer.
// Return Value:
// - Read/write span of OutputCells
gsl::span<OutputCell> OutputCellRect::GetRow(const size_t row)
gsl::span<OutputCell> OutputCellRect::GetRow(const til::CoordType row)
{
return gsl::span<OutputCell>(_FindRowOffset(row), _cols);
}
@@ -48,7 +45,7 @@ gsl::span<OutputCell> OutputCellRect::GetRow(const size_t row)
// - row - The Y position or row index in the buffer.
// Return Value:
// - Read-only iterator of OutputCells
OutputCellIterator OutputCellRect::GetRowIter(const size_t row) const
OutputCellIterator OutputCellRect::GetRowIter(const til::CoordType row) const
{
const gsl::span<const OutputCell> view(_FindRowOffset(row), _cols);
@@ -62,9 +59,9 @@ OutputCellIterator OutputCellRect::GetRowIter(const size_t row) const
// - row - The Y position or row index in the buffer.
// Return Value:
// - Pointer to the location in the rectangle that represents the start of the requested row.
OutputCell* OutputCellRect::_FindRowOffset(const size_t row)
OutputCell* OutputCellRect::_FindRowOffset(const til::CoordType row)
{
return &_storage.at(row * _cols);
return &_storage.at(gsl::narrow_cast<size_t>(row * _cols));
}
// Routine Description:
@@ -74,16 +71,16 @@ OutputCell* OutputCellRect::_FindRowOffset(const size_t row)
// - row - The Y position or row index in the buffer.
// Return Value:
// - Pointer to the location in the rectangle that represents the start of the requested row.
const OutputCell* OutputCellRect::_FindRowOffset(const size_t row) const
const OutputCell* OutputCellRect::_FindRowOffset(const til::CoordType row) const
{
return &_storage.at(row * _cols);
return &_storage.at(gsl::narrow_cast<size_t>(row * _cols));
}
// Routine Description:
// - Gets the height of the rectangle
// Return Value:
// - Height
size_t OutputCellRect::Height() const noexcept
til::CoordType OutputCellRect::Height() const noexcept
{
return _rows;
}
@@ -92,7 +89,7 @@ size_t OutputCellRect::Height() const noexcept
// - Gets the width of the rectangle
// Return Value:
// - Width
size_t OutputCellRect::Width() const noexcept
til::CoordType OutputCellRect::Width() const noexcept
{
return _cols;
}

View File

@@ -30,20 +30,20 @@ class OutputCellRect final
{
public:
OutputCellRect() noexcept;
OutputCellRect(const size_t rows, const size_t cols);
OutputCellRect(const til::CoordType rows, const til::CoordType cols);
gsl::span<OutputCell> GetRow(const size_t row);
OutputCellIterator GetRowIter(const size_t row) const;
gsl::span<OutputCell> GetRow(const til::CoordType row);
OutputCellIterator GetRowIter(const til::CoordType row) const;
size_t Height() const noexcept;
size_t Width() const noexcept;
til::CoordType Height() const noexcept;
til::CoordType Width() const noexcept;
private:
std::vector<OutputCell> _storage;
OutputCell* _FindRowOffset(const size_t row);
const OutputCell* _FindRowOffset(const size_t row) const;
OutputCell* _FindRowOffset(const til::CoordType row);
const OutputCell* _FindRowOffset(const til::CoordType row) const;
size_t _cols;
size_t _rows;
til::CoordType _cols;
til::CoordType _rows;
};

View File

@@ -38,7 +38,7 @@ OutputCellView::OutputCellView(const std::wstring_view view,
// - Reports how many columns we expect the Chars() text data to consume
// Return Value:
// - Count of column cells on the screen
size_t OutputCellView::Columns() const noexcept
til::CoordType OutputCellView::Columns() const noexcept
{
if (DbcsAttr().IsSingle())
{

View File

@@ -31,7 +31,7 @@ public:
const TextAttributeBehavior behavior) noexcept;
const std::wstring_view& Chars() const noexcept;
size_t Columns() const noexcept;
til::CoordType Columns() const noexcept;
DbcsAttribute DbcsAttr() const noexcept;
TextAttribute TextAttr() const noexcept;
TextAttributeBehavior TextAttrBehavior() const noexcept;

View File

@@ -16,7 +16,7 @@
// - pParent - the text buffer that this row belongs to
// Return Value:
// - constructed object
ROW::ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent) :
ROW::ROW(const til::CoordType rowId, const til::CoordType rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent) :
_id{ rowId },
_rowWidth{ rowWidth },
_charRow{ rowWidth, this },
@@ -58,7 +58,7 @@ bool ROW::Reset(const TextAttribute Attr)
// - width - the new width, in cells
// Return Value:
// - S_OK if successful, otherwise relevant error
[[nodiscard]] HRESULT ROW::Resize(const unsigned short width)
[[nodiscard]] HRESULT ROW::Resize(const til::CoordType width)
{
RETURN_IF_FAILED(_charRow.Resize(width));
try
@@ -78,7 +78,7 @@ bool ROW::Reset(const TextAttribute Attr)
// - column - 0-indexed column index
// Return Value:
// - <none>
void ROW::ClearColumn(const size_t column)
void ROW::ClearColumn(const til::CoordType column)
{
THROW_HR_IF(E_INVALIDARG, column >= _charRow.size());
_charRow.ClearCell(column);
@@ -103,7 +103,7 @@ const UnicodeStorage& ROW::GetUnicodeStorage() const noexcept
// - limitRight - right inclusive column ID for the last write in this row. (optional, will just write to the end of row if nullopt)
// Return Value:
// - iterator to first cell that was not written to this row.
OutputCellIterator ROW::WriteCells(OutputCellIterator it, const size_t index, const std::optional<bool> wrap, std::optional<size_t> limitRight)
OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType index, const std::optional<bool> wrap, std::optional<til::CoordType> limitRight)
{
THROW_HR_IF(E_INVALIDARG, index >= _charRow.size());
THROW_HR_IF(E_INVALIDARG, limitRight.value_or(0) >= _charRow.size());

View File

@@ -32,9 +32,9 @@ class TextBuffer;
class ROW final
{
public:
ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent);
ROW(const til::CoordType rowId, const til::CoordType rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent);
size_t size() const noexcept { return _rowWidth; }
til::CoordType size() const noexcept { return _rowWidth; }
void SetWrapForced(const bool wrap) noexcept { _wrapForced = wrap; }
bool WasWrapForced() const noexcept { return _wrapForced; }
@@ -51,19 +51,19 @@ public:
LineRendition GetLineRendition() const noexcept { return _lineRendition; }
void SetLineRendition(const LineRendition lineRendition) noexcept { _lineRendition = lineRendition; }
SHORT GetId() const noexcept { return _id; }
void SetId(const SHORT id) noexcept { _id = id; }
til::CoordType GetId() const noexcept { return _id; }
void SetId(const til::CoordType id) noexcept { _id = id; }
bool Reset(const TextAttribute Attr);
[[nodiscard]] HRESULT Resize(const unsigned short width);
[[nodiscard]] HRESULT Resize(const til::CoordType width);
void ClearColumn(const size_t column);
void ClearColumn(const til::CoordType column);
std::wstring GetText() const { return _charRow.GetText(); }
UnicodeStorage& GetUnicodeStorage() noexcept;
const UnicodeStorage& GetUnicodeStorage() const noexcept;
OutputCellIterator WriteCells(OutputCellIterator it, const size_t index, const std::optional<bool> wrap = std::nullopt, std::optional<size_t> limitRight = std::nullopt);
OutputCellIterator WriteCells(OutputCellIterator it, const til::CoordType index, const std::optional<bool> wrap = std::nullopt, std::optional<til::CoordType> limitRight = std::nullopt);
#ifdef UNIT_TESTING
friend constexpr bool operator==(const ROW& a, const ROW& b) noexcept;
@@ -74,8 +74,8 @@ private:
CharRow _charRow;
ATTR_ROW _attrRow;
LineRendition _lineRendition;
SHORT _id;
unsigned short _rowWidth;
til::CoordType _id;
til::CoordType _rowWidth;
// Occurs when the user runs out of text in a given row and we're forced to wrap the cursor to the next line
bool _wrapForced;
// Occurs when the user runs out of text to support a double byte character and we're forced to the next line

View File

@@ -357,6 +357,11 @@ void TextAttribute::SetReverseVideo(bool isReversed) noexcept
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO, isReversed);
}
ExtendedAttributes TextAttribute::GetExtendedAttributes() const noexcept
{
return _extendedAttrs;
}
// Routine Description:
// - swaps foreground and background color
void TextAttribute::Invert() noexcept

View File

@@ -109,10 +109,7 @@ public:
void SetOverlined(bool isOverlined) noexcept;
void SetReverseVideo(bool isReversed) noexcept;
constexpr ExtendedAttributes GetExtendedAttributes() const noexcept
{
return _extendedAttrs;
}
ExtendedAttributes GetExtendedAttributes() const noexcept;
bool IsHyperlink() const noexcept;
@@ -164,13 +161,6 @@ public:
{
return WI_IsAnyFlagSet(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL | COMMON_LVB_GRID_LVERTICAL | COMMON_LVB_GRID_RVERTICAL | COMMON_LVB_UNDERSCORE);
}
constexpr bool HasAnyExtendedAttributes() const noexcept
{
return GetExtendedAttributes() != ExtendedAttributes::Normal ||
IsAnyGridLineEnabled() ||
GetHyperlinkId() != 0 ||
IsReverseVideo();
}
private:
static std::array<TextColor, 16> s_legacyForegroundColorMap;

View File

@@ -49,6 +49,8 @@ enum class ColorAlias : size_t
{
DefaultForeground,
DefaultBackground,
FrameForeground,
FrameBackground,
ENUM_COUNT // must be the last element in the enum class
};
@@ -72,10 +74,13 @@ public:
static constexpr BYTE BRIGHT_CYAN = 14;
static constexpr BYTE BRIGHT_WHITE = 15;
static constexpr size_t DEFAULT_FOREGROUND = 256;
static constexpr size_t DEFAULT_BACKGROUND = 257;
static constexpr size_t CURSOR_COLOR = 258;
static constexpr size_t TABLE_SIZE = 259;
// Entries 256 to 260 are reserved for XTerm compatibility.
static constexpr size_t DEFAULT_FOREGROUND = 261;
static constexpr size_t DEFAULT_BACKGROUND = 262;
static constexpr size_t FRAME_FOREGROUND = 263;
static constexpr size_t FRAME_BACKGROUND = 264;
static constexpr size_t CURSOR_COLOR = 265;
static constexpr size_t TABLE_SIZE = 266;
constexpr TextColor() noexcept :
_meta{ ColorType::IsDefault },

View File

@@ -47,7 +47,7 @@ void UnicodeStorage::Erase(const key_type key) noexcept
// - rowMap - A map of the old row IDs to the new row IDs.
// - width - The width of the new row. Remove any items that are beyond the row width.
// - Use nullopt if we're not resizing the width of the row, just renumbering the rows.
void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width)
void UnicodeStorage::Remap(const std::unordered_map<til::CoordType, til::CoordType>& rowMap, const std::optional<til::CoordType> width)
{
// Make a temporary map to hold all the new row positioning
std::unordered_map<key_type, mapped_type> newMap;
@@ -87,7 +87,7 @@ void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const
const auto newRowId = mapIter->second;
// Generate a new coordinate with the same X as the old one, but a new Y value.
const auto newCoord = COORD{ oldCoord.X, newRowId };
const auto newCoord = til::point{ oldCoord.X, newRowId };
// Put the adjusted coordinate into the map with the original value.
newMap.emplace(newCoord, pair.second);

View File

@@ -20,11 +20,11 @@ Author(s):
#include <til/bit.h>
#include <til/hash.h>
// std::unordered_map needs help to know how to hash a COORD
// std::unordered_map needs help to know how to hash a til::point
namespace std
{
template<>
struct hash<COORD>
struct hash<til::point>
{
// Routine Description:
// - hashes a coord. coord will be hashed by storing the x and y values consecutively in the lower
@@ -33,9 +33,9 @@ namespace std
// - coord - the coord to hash
// Return Value:
// - the hashed coord
constexpr size_t operator()(const COORD& coord) const noexcept
constexpr size_t operator()(const til::point coord) const noexcept
{
return til::hash(til::bit_cast<uint32_t>(coord));
return til::hash(til::bit_cast<uint64_t>(coord));
}
};
}
@@ -43,7 +43,7 @@ namespace std
class UnicodeStorage final
{
public:
using key_type = typename COORD;
using key_type = typename til::point;
using mapped_type = typename std::vector<wchar_t>;
UnicodeStorage() noexcept;
@@ -54,7 +54,7 @@ public:
void Erase(const key_type key) noexcept;
void Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width);
void Remap(const std::unordered_map<til::CoordType, til::CoordType>& rowMap, const std::optional<til::CoordType> width);
private:
std::unordered_map<key_type, mapped_type> _map;

View File

@@ -13,7 +13,6 @@
// - ulSize - The height of the cursor within this buffer
Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept :
_parentBuffer{ parentBuffer },
_cPosition{ 0 },
_fHasMoved(false),
_fIsVisible(true),
_fIsOn(true),
@@ -23,7 +22,6 @@ Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept :
_fIsConversionArea(false),
_fIsPopupShown(false),
_fDelayedEolWrap(false),
_coordDelayedAt{ 0 },
_fDeferCursorRedraw(false),
_fHaveDeferredCursorRedraw(false),
_ulSize(ulSize),
@@ -35,7 +33,7 @@ Cursor::~Cursor()
{
}
COORD Cursor::GetPosition() const noexcept
til::point Cursor::GetPosition() const noexcept
{
return _cPosition;
}
@@ -192,59 +190,58 @@ void Cursor::_RedrawCursorAlways() noexcept
CATCH_LOG();
}
void Cursor::SetPosition(const COORD cPosition) noexcept
void Cursor::SetPosition(const til::point cPosition) noexcept
{
_RedrawCursor();
_cPosition.X = cPosition.X;
_cPosition.Y = cPosition.Y;
_cPosition = cPosition;
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::SetXPosition(const int NewX) noexcept
void Cursor::SetXPosition(const til::CoordType NewX) noexcept
{
_RedrawCursor();
_cPosition.X = gsl::narrow<SHORT>(NewX);
_cPosition.X = NewX;
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::SetYPosition(const int NewY) noexcept
void Cursor::SetYPosition(const til::CoordType NewY) noexcept
{
_RedrawCursor();
_cPosition.Y = gsl::narrow<SHORT>(NewY);
_cPosition.Y = NewY;
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::IncrementXPosition(const int DeltaX) noexcept
void Cursor::IncrementXPosition(const til::CoordType DeltaX) noexcept
{
_RedrawCursor();
_cPosition.X += gsl::narrow<SHORT>(DeltaX);
_cPosition.X += DeltaX;
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::IncrementYPosition(const int DeltaY) noexcept
void Cursor::IncrementYPosition(const til::CoordType DeltaY) noexcept
{
_RedrawCursor();
_cPosition.Y += gsl::narrow<SHORT>(DeltaY);
_cPosition.Y += DeltaY;
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::DecrementXPosition(const int DeltaX) noexcept
void Cursor::DecrementXPosition(const til::CoordType DeltaX) noexcept
{
_RedrawCursor();
_cPosition.X -= gsl::narrow<SHORT>(DeltaX);
_cPosition.X -= DeltaX;
_RedrawCursor();
ResetDelayEOLWrap();
}
void Cursor::DecrementYPosition(const int DeltaY) noexcept
void Cursor::DecrementYPosition(const til::CoordType DeltaY) noexcept
{
_RedrawCursor();
_cPosition.Y -= gsl::narrow<SHORT>(DeltaY);
_cPosition.Y -= DeltaY;
_RedrawCursor();
ResetDelayEOLWrap();
}
@@ -284,7 +281,7 @@ void Cursor::CopyProperties(const Cursor& OtherCursor) noexcept
_cursorType = OtherCursor._cursorType;
}
void Cursor::DelayEOLWrap(const COORD coordDelayedAt) noexcept
void Cursor::DelayEOLWrap(const til::point coordDelayedAt) noexcept
{
_coordDelayedAt = coordDelayedAt;
_fDelayedEolWrap = true;
@@ -292,11 +289,11 @@ void Cursor::DelayEOLWrap(const COORD coordDelayedAt) noexcept
void Cursor::ResetDelayEOLWrap() noexcept
{
_coordDelayedAt = { 0 };
_coordDelayedAt = {};
_fDelayedEolWrap = false;
}
COORD Cursor::GetDelayedAtPosition() const noexcept
til::point Cursor::GetDelayedAtPosition() const noexcept
{
return _coordDelayedAt;
}

View File

@@ -47,7 +47,7 @@ public:
bool IsPopupShown() const noexcept;
bool GetDelay() const noexcept;
ULONG GetSize() const noexcept;
COORD GetPosition() const noexcept;
til::point GetPosition() const noexcept;
const CursorType GetType() const noexcept;
@@ -66,19 +66,19 @@ public:
void SetSize(const ULONG ulSize) noexcept;
void SetStyle(const ULONG ulSize, const CursorType type) noexcept;
void SetPosition(const COORD cPosition) noexcept;
void SetXPosition(const int NewX) noexcept;
void SetYPosition(const int NewY) noexcept;
void IncrementXPosition(const int DeltaX) noexcept;
void IncrementYPosition(const int DeltaY) noexcept;
void DecrementXPosition(const int DeltaX) noexcept;
void DecrementYPosition(const int DeltaY) noexcept;
void SetPosition(const til::point cPosition) noexcept;
void SetXPosition(const til::CoordType NewX) noexcept;
void SetYPosition(const til::CoordType NewY) noexcept;
void IncrementXPosition(const til::CoordType DeltaX) noexcept;
void IncrementYPosition(const til::CoordType DeltaY) noexcept;
void DecrementXPosition(const til::CoordType DeltaX) noexcept;
void DecrementYPosition(const til::CoordType DeltaY) noexcept;
void CopyProperties(const Cursor& OtherCursor) noexcept;
void DelayEOLWrap(const COORD coordDelayedAt) noexcept;
void DelayEOLWrap(const til::point coordDelayedAt) noexcept;
void ResetDelayEOLWrap() noexcept;
COORD GetDelayedAtPosition() const noexcept;
til::point GetDelayedAtPosition() const noexcept;
bool IsDelayedEOLWrap() const noexcept;
void SetType(const CursorType type) noexcept;
@@ -90,7 +90,7 @@ private:
// NOTE: If you are adding a property here, go add it to CopyProperties.
COORD _cPosition; // current position on screen (in screen buffer coords).
til::point _cPosition; // current position on screen (in screen buffer coords).
bool _fHasMoved;
bool _fIsVisible; // whether cursor is visible (set only through the API)
@@ -102,7 +102,7 @@ private:
bool _fIsPopupShown; // if a popup is being shown, turn off, stop blinking.
bool _fDelayedEolWrap; // don't wrap at EOL till the next char comes in.
COORD _coordDelayedAt; // coordinate the EOL wrap was delayed at.
til::point _coordDelayedAt; // coordinate the EOL wrap was delayed at.
bool _fDeferCursorRedraw; // whether we should defer redrawing the cursor or not
bool _fHaveDeferredCursorRedraw; // have we been asked to redraw the cursor while it was being deferred?

View File

@@ -35,7 +35,6 @@ Abstract:
#include <intsafe.h>
// private dependencies
#include "../inc/operators.hpp"
#include "../inc/unicode.hpp"
#pragma warning(pop)

View File

@@ -50,7 +50,7 @@ Search::Search(IUiaData& uiaData,
const std::wstring& str,
const Direction direction,
const Sensitivity sensitivity,
const COORD anchor) :
const til::point anchor) :
_direction(direction),
_sensitivity(sensitivity),
_needle(s_CreateNeedleFromString(str)),
@@ -124,7 +124,7 @@ void Search::Color(const TextAttribute attr) const
// been called and returned true.
// Return Value:
// - pair containing [start, end] coord positions of text found by search
std::pair<COORD, COORD> Search::GetFoundLocation() const noexcept
std::pair<til::point, til::point> Search::GetFoundLocation() const noexcept
{
return { _coordSelStart, _coordSelEnd };
}
@@ -140,7 +140,7 @@ std::pair<COORD, COORD> Search::GetFoundLocation() const noexcept
// - direction - The intended direction of the search
// Return Value:
// - Coordinate to start the search from.
COORD Search::s_GetInitialAnchor(const IUiaData& uiaData, const Direction direction)
til::point Search::s_GetInitialAnchor(const IUiaData& uiaData, const Direction direction)
{
const auto& textBuffer = uiaData.GetTextBuffer();
const auto textBufferEndPosition = uiaData.GetTextBufferEndPosition();
@@ -187,10 +187,10 @@ COORD Search::s_GetInitialAnchor(const IUiaData& uiaData, const Direction direct
// - end - If we found it, this is filled with the coordinate of the last character of the needle.
// Return Value:
// - True if we found it. False if not.
bool Search::_FindNeedleInHaystackAt(const COORD pos, COORD& start, COORD& end) const
bool Search::_FindNeedleInHaystackAt(const til::point pos, til::point& start, til::point& end) const
{
start = { 0 };
end = { 0 };
start = {};
end = {};
auto bufferPos = pos;
@@ -269,7 +269,7 @@ wchar_t Search::_ApplySensitivity(const wchar_t wch) const noexcept
// - Helper to increment a coordinate in respect to the associated screen buffer
// Arguments
// - coord - Updated by function to increment one position (will wrap X and Y direction)
void Search::_IncrementCoord(COORD& coord) const noexcept
void Search::_IncrementCoord(til::point& coord) const noexcept
{
_uiaData.GetTextBuffer().GetSize().IncrementInBoundsCircular(coord);
}
@@ -278,7 +278,7 @@ void Search::_IncrementCoord(COORD& coord) const noexcept
// - Helper to decrement a coordinate in respect to the associated screen buffer
// Arguments
// - coord - Updated by function to decrement one position (will wrap X and Y direction)
void Search::_DecrementCoord(COORD& coord) const noexcept
void Search::_DecrementCoord(til::point& coord) const noexcept
{
_uiaData.GetTextBuffer().GetSize().DecrementInBoundsCircular(coord);
}
@@ -314,7 +314,7 @@ void Search::_UpdateNextPosition()
{
if (_direction == Direction::Forward)
{
_coordNext = { 0 };
_coordNext = {};
}
else
{

View File

@@ -49,33 +49,33 @@ public:
const std::wstring& str,
const Direction dir,
const Sensitivity sensitivity,
const COORD anchor);
const til::point anchor);
bool FindNext();
void Select() const;
void Color(const TextAttribute attr) const;
std::pair<COORD, COORD> GetFoundLocation() const noexcept;
std::pair<til::point, til::point> GetFoundLocation() const noexcept;
private:
wchar_t _ApplySensitivity(const wchar_t wch) const noexcept;
bool _FindNeedleInHaystackAt(const COORD pos, COORD& start, COORD& end) const;
bool _FindNeedleInHaystackAt(const til::point pos, til::point& start, til::point& end) const;
bool _CompareChars(const std::wstring_view one, const std::wstring_view two) const noexcept;
void _UpdateNextPosition();
void _IncrementCoord(COORD& coord) const noexcept;
void _DecrementCoord(COORD& coord) const noexcept;
void _IncrementCoord(til::point& coord) const noexcept;
void _DecrementCoord(til::point& coord) const noexcept;
static COORD s_GetInitialAnchor(const Microsoft::Console::Types::IUiaData& uiaData, const Direction dir);
static til::point s_GetInitialAnchor(const Microsoft::Console::Types::IUiaData& uiaData, const Direction dir);
static std::vector<std::vector<wchar_t>> s_CreateNeedleFromString(const std::wstring& wstr);
bool _reachedEnd = false;
COORD _coordNext = { 0 };
COORD _coordSelStart = { 0 };
COORD _coordSelEnd = { 0 };
til::point _coordNext;
til::point _coordSelStart;
til::point _coordSelEnd;
const COORD _coordAnchor;
const til::point _coordAnchor;
const std::vector<std::vector<wchar_t>> _needle;
const Direction _direction;
const Sensitivity _sensitivity;

View File

@@ -30,7 +30,7 @@ using PointTree = interval_tree::IntervalTree<til::point, size_t>;
// Return Value:
// - constructed object
// Note: may throw exception
TextBuffer::TextBuffer(const COORD screenBufferSize,
TextBuffer::TextBuffer(const til::size screenBufferSize,
const TextAttribute defaultAttributes,
const UINT cursorSize,
const bool isActiveBuffer,
@@ -47,10 +47,10 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
_currentPatternId{ 0 }
{
// initialize ROWs
_storage.reserve(static_cast<size_t>(screenBufferSize.Y));
for (size_t i = 0; i < static_cast<size_t>(screenBufferSize.Y); ++i)
_storage.reserve(gsl::narrow<size_t>(screenBufferSize.Y));
for (til::CoordType i = 0; i < screenBufferSize.Y; ++i)
{
_storage.emplace_back(static_cast<SHORT>(i), screenBufferSize.X, _currentAttributes, this);
_storage.emplace_back(i, screenBufferSize.X, _currentAttributes, this);
}
_UpdateSize();
@@ -74,9 +74,9 @@ void TextBuffer::CopyProperties(const TextBuffer& OtherBuffer) noexcept
// - <none>
// Return Value:
// - Total number of rows in the buffer
UINT TextBuffer::TotalRowCount() const noexcept
til::CoordType TextBuffer::TotalRowCount() const noexcept
{
return gsl::narrow<UINT>(_storage.size());
return gsl::narrow_cast<til::CoordType>(_storage.size());
}
// Routine Description:
@@ -86,13 +86,11 @@ UINT TextBuffer::TotalRowCount() const noexcept
// - Number of rows down from the first row of the buffer.
// Return Value:
// - const reference to the requested row. Asserts if out of bounds.
const ROW& TextBuffer::GetRowByOffset(const size_t index) const
const ROW& TextBuffer::GetRowByOffset(const til::CoordType index) const noexcept
{
const size_t totalRows = TotalRowCount();
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
const auto offsetIndex = (_firstRow + index) % totalRows;
return _storage.at(offsetIndex);
const auto offsetIndex = gsl::narrow_cast<size_t>(_firstRow + index) % _storage.size();
return til::at(_storage, offsetIndex);
}
// Routine Description:
@@ -102,13 +100,11 @@ const ROW& TextBuffer::GetRowByOffset(const size_t index) const
// - Number of rows down from the first row of the buffer.
// Return Value:
// - reference to the requested row. Asserts if out of bounds.
ROW& TextBuffer::GetRowByOffset(const size_t index)
ROW& TextBuffer::GetRowByOffset(const til::CoordType index) noexcept
{
const size_t totalRows = TotalRowCount();
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
const auto offsetIndex = (_firstRow + index) % totalRows;
return _storage.at(offsetIndex);
const auto offsetIndex = gsl::narrow_cast<size_t>(_firstRow + index) % _storage.size();
return til::at(_storage, offsetIndex);
}
// Routine Description:
@@ -117,7 +113,7 @@ ROW& TextBuffer::GetRowByOffset(const size_t index)
// - at - X,Y position in buffer for iterator start position
// Return Value:
// - Read-only iterator of text data only.
TextBufferTextIterator TextBuffer::GetTextDataAt(const COORD at) const
TextBufferTextIterator TextBuffer::GetTextDataAt(const til::point at) const
{
return TextBufferTextIterator(GetCellDataAt(at));
}
@@ -128,7 +124,7 @@ TextBufferTextIterator TextBuffer::GetTextDataAt(const COORD at) const
// - at - X,Y position in buffer for iterator start position
// Return Value:
// - Read-only iterator of cell data.
TextBufferCellIterator TextBuffer::GetCellDataAt(const COORD at) const
TextBufferCellIterator TextBuffer::GetCellDataAt(const til::point at) const
{
return TextBufferCellIterator(*this, at);
}
@@ -140,7 +136,7 @@ TextBufferCellIterator TextBuffer::GetCellDataAt(const COORD at) const
// - at - X,Y position in buffer for iterator start position
// Return Value:
// - Read-only iterator of text data only.
TextBufferTextIterator TextBuffer::GetTextLineDataAt(const COORD at) const
TextBufferTextIterator TextBuffer::GetTextLineDataAt(const til::point at) const
{
return TextBufferTextIterator(GetCellLineDataAt(at));
}
@@ -152,9 +148,9 @@ TextBufferTextIterator TextBuffer::GetTextLineDataAt(const COORD at) const
// - at - X,Y position in buffer for iterator start position
// Return Value:
// - Read-only iterator of cell data.
TextBufferCellIterator TextBuffer::GetCellLineDataAt(const COORD at) const
TextBufferCellIterator TextBuffer::GetCellLineDataAt(const til::point at) const
{
SMALL_RECT limit;
til::inclusive_rect limit;
limit.Top = at.Y;
limit.Bottom = at.Y;
limit.Left = 0;
@@ -171,7 +167,7 @@ TextBufferCellIterator TextBuffer::GetCellLineDataAt(const COORD at) const
// - limit - boundaries for the iterator to operate within
// Return Value:
// - Read-only iterator of text data only.
TextBufferTextIterator TextBuffer::GetTextDataAt(const COORD at, const Viewport limit) const
TextBufferTextIterator TextBuffer::GetTextDataAt(const til::point at, const Viewport limit) const
{
return TextBufferTextIterator(GetCellDataAt(at, limit));
}
@@ -184,7 +180,7 @@ TextBufferTextIterator TextBuffer::GetTextDataAt(const COORD at, const Viewport
// - limit - boundaries for the iterator to operate within
// Return Value:
// - Read-only iterator of cell data.
TextBufferCellIterator TextBuffer::GetCellDataAt(const COORD at, const Viewport limit) const
TextBufferCellIterator TextBuffer::GetCellDataAt(const til::point at, const Viewport limit) const
{
return TextBufferCellIterator(*this, at, limit);
}
@@ -337,7 +333,7 @@ OutputCellIterator TextBuffer::Write(const OutputCellIterator givenIt)
// Return Value:
// - The final position of the iterator
OutputCellIterator TextBuffer::Write(const OutputCellIterator givenIt,
const COORD target,
const til::point target,
const std::optional<bool> wrap)
{
// Make mutable copy so we can walk.
@@ -374,9 +370,9 @@ OutputCellIterator TextBuffer::Write(const OutputCellIterator givenIt,
// Return Value:
// - The iterator, but advanced to where we stopped writing. Use to find input consumed length or cells written length.
OutputCellIterator TextBuffer::WriteLine(const OutputCellIterator givenIt,
const COORD target,
const til::point target,
const std::optional<bool> wrap,
std::optional<size_t> limitRight)
std::optional<til::CoordType> limitRight)
{
// If we're not in bounds, exit early.
if (!GetSize().IsInBounds(target))
@@ -390,7 +386,7 @@ OutputCellIterator TextBuffer::WriteLine(const OutputCellIterator givenIt,
// Take the cell distance written and notify that it needs to be repainted.
const auto written = newIt.GetCellDistance(givenIt);
const auto paint = Viewport::FromDimensions(target, { gsl::narrow<SHORT>(written), 1 });
const auto paint = Viewport::FromDimensions(target, { written, 1 });
TriggerRedraw(paint);
return newIt;
@@ -467,7 +463,7 @@ bool TextBuffer::InsertCharacter(const wchar_t wch, const DbcsAttribute dbcsAttr
// - <none> - Always sets to wrap
//Return Value:
// - <none>
void TextBuffer::_SetWrapOnCurrentRow()
void TextBuffer::_SetWrapOnCurrentRow() noexcept
{
_AdjustWrapOnCurrentRow(true);
}
@@ -479,10 +475,10 @@ void TextBuffer::_SetWrapOnCurrentRow()
// - fSet - True if this row has a wrap. False otherwise.
//Return Value:
// - <none>
void TextBuffer::_AdjustWrapOnCurrentRow(const bool fSet)
void TextBuffer::_AdjustWrapOnCurrentRow(const bool fSet) noexcept
{
// The vertical position of the cursor represents the current row we're manipulating.
const UINT uiCurrentRowOffset = GetCursor().GetPosition().Y;
const auto uiCurrentRowOffset = GetCursor().GetPosition().Y;
// Set the wrap status as appropriate
GetRowByOffset(uiCurrentRowOffset).SetWrapForced(fSet);
@@ -501,7 +497,7 @@ bool TextBuffer::IncrementCursor()
// Cursor position is stored as logical array indices (starts at 0) for the window
// Buffer Size is specified as the "length" of the array. It would say 80 for valid values of 0-79.
// So subtract 1 from buffer size in each direction to find the index of the final column in the buffer
const short iFinalColumnIndex = GetLineWidth(GetCursor().GetPosition().Y) - 1;
const auto iFinalColumnIndex = GetLineWidth(GetCursor().GetPosition().Y) - 1;
// Move the cursor one position to the right
GetCursor().IncrementXPosition(1);
@@ -604,17 +600,17 @@ bool TextBuffer::IncrementCircularBuffer(const bool inVtMode)
// - The viewport
//Return value:
// - Coordinate position (relative to the text buffer)
COORD TextBuffer::GetLastNonSpaceCharacter(std::optional<const Microsoft::Console::Types::Viewport> viewOptional) const
til::point TextBuffer::GetLastNonSpaceCharacter(std::optional<const Microsoft::Console::Types::Viewport> viewOptional) const
{
const auto viewport = viewOptional.has_value() ? viewOptional.value() : GetSize();
COORD coordEndOfText = { 0 };
til::point coordEndOfText;
// Search the given viewport by starting at the bottom.
coordEndOfText.Y = viewport.BottomInclusive();
const auto& currRow = GetRowByOffset(coordEndOfText.Y);
// The X position of the end of the valid text is the Right draw boundary (which is one beyond the final valid character)
coordEndOfText.X = gsl::narrow<short>(currRow.GetCharRow().MeasureRight()) - 1;
coordEndOfText.X = currRow.GetCharRow().MeasureRight() - 1;
// If the X coordinate turns out to be -1, the row was empty, we need to search backwards for the real end of text.
const auto viewportTop = viewport.Top();
@@ -625,13 +621,13 @@ COORD TextBuffer::GetLastNonSpaceCharacter(std::optional<const Microsoft::Consol
const auto& backupRow = GetRowByOffset(coordEndOfText.Y);
// We need to back up to the previous row if this line is empty, AND there are more rows
coordEndOfText.X = gsl::narrow<short>(backupRow.GetCharRow().MeasureRight()) - 1;
coordEndOfText.X = backupRow.GetCharRow().MeasureRight() - 1;
fDoBackUp = (coordEndOfText.X < 0 && coordEndOfText.Y > viewportTop);
}
// don't allow negative results
coordEndOfText.Y = std::max(coordEndOfText.Y, 0i16);
coordEndOfText.X = std::max(coordEndOfText.X, 0i16);
coordEndOfText.Y = std::max(coordEndOfText.Y, 0);
coordEndOfText.X = std::max(coordEndOfText.X, 0);
return coordEndOfText;
}
@@ -643,7 +639,7 @@ COORD TextBuffer::GetLastNonSpaceCharacter(std::optional<const Microsoft::Consol
// Return Value:
// - Coordinate position in screen coordinates of the character just before the cursor.
// - NOTE: Will return 0,0 if already in the top left corner
COORD TextBuffer::_GetPreviousFromCursor() const
til::point TextBuffer::_GetPreviousFromCursor() const noexcept
{
auto coordPosition = GetCursor().GetPosition();
@@ -668,7 +664,7 @@ COORD TextBuffer::_GetPreviousFromCursor() const
return coordPosition;
}
const SHORT TextBuffer::GetFirstRowIndex() const noexcept
const til::CoordType TextBuffer::GetFirstRowIndex() const noexcept
{
return _firstRow;
}
@@ -680,15 +676,15 @@ const Viewport TextBuffer::GetSize() const noexcept
void TextBuffer::_UpdateSize()
{
_size = Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
_size = Viewport::FromDimensions({ _storage.at(0).size(), gsl::narrow<til::CoordType>(_storage.size()) });
}
void TextBuffer::_SetFirstRowIndex(const SHORT FirstRowIndex) noexcept
void TextBuffer::_SetFirstRowIndex(const til::CoordType FirstRowIndex) noexcept
{
_firstRow = FirstRowIndex;
}
void TextBuffer::ScrollRows(const SHORT firstRow, const SHORT size, const SHORT delta)
void TextBuffer::ScrollRows(const til::CoordType firstRow, const til::CoordType size, const til::CoordType delta)
{
// If we don't have to move anything, leave early.
if (delta == 0)
@@ -825,9 +821,9 @@ void TextBuffer::SetCurrentLineRendition(const LineRendition lineRendition)
const auto fillChar = L' ';
auto fillAttrs = GetCurrentAttributes();
fillAttrs.SetStandardErase();
const size_t fillOffset = GetLineWidth(rowIndex);
const auto fillLength = GetSize().Width() - fillOffset;
const auto fillData = OutputCellIterator{ fillChar, fillAttrs, fillLength };
const auto fillOffset = GetLineWidth(rowIndex);
const auto fillLength = gsl::narrow<size_t>(GetSize().Width() - fillOffset);
const OutputCellIterator fillData{ fillChar, fillAttrs, fillLength };
row.WriteCells(fillData, fillOffset, false);
// We also need to make sure the cursor is clamped within the new width.
GetCursor().SetPosition(ClampPositionWithinLine(cursorPosition));
@@ -836,7 +832,7 @@ void TextBuffer::SetCurrentLineRendition(const LineRendition lineRendition)
}
}
void TextBuffer::ResetLineRenditionRange(const size_t startRow, const size_t endRow)
void TextBuffer::ResetLineRenditionRange(const til::CoordType startRow, const til::CoordType endRow) noexcept
{
for (auto row = startRow; row < endRow; row++)
{
@@ -844,40 +840,40 @@ void TextBuffer::ResetLineRenditionRange(const size_t startRow, const size_t end
}
}
LineRendition TextBuffer::GetLineRendition(const size_t row) const
LineRendition TextBuffer::GetLineRendition(const til::CoordType row) const noexcept
{
return GetRowByOffset(row).GetLineRendition();
}
bool TextBuffer::IsDoubleWidthLine(const size_t row) const
bool TextBuffer::IsDoubleWidthLine(const til::CoordType row) const noexcept
{
return GetLineRendition(row) != LineRendition::SingleWidth;
}
SHORT TextBuffer::GetLineWidth(const size_t row) const
til::CoordType TextBuffer::GetLineWidth(const til::CoordType row) const noexcept
{
// Use shift right to quickly divide the width by 2 for double width lines.
const SHORT scale = IsDoubleWidthLine(row) ? 1 : 0;
const auto scale = IsDoubleWidthLine(row) ? 1 : 0;
return GetSize().Width() >> scale;
}
COORD TextBuffer::ClampPositionWithinLine(const COORD position) const
til::point TextBuffer::ClampPositionWithinLine(const til::point position) const noexcept
{
const SHORT rightmostColumn = GetLineWidth(position.Y) - 1;
const auto rightmostColumn = GetLineWidth(position.Y) - 1;
return { std::min(position.X, rightmostColumn), position.Y };
}
COORD TextBuffer::ScreenToBufferPosition(const COORD position) const
til::point TextBuffer::ScreenToBufferPosition(const til::point position) const noexcept
{
// Use shift right to quickly divide the X pos by 2 for double width lines.
const SHORT scale = IsDoubleWidthLine(position.Y) ? 1 : 0;
const auto scale = IsDoubleWidthLine(position.Y) ? 1 : 0;
return { position.X >> scale, position.Y };
}
COORD TextBuffer::BufferToScreenPosition(const COORD position) const
til::point TextBuffer::BufferToScreenPosition(const til::point position) const noexcept
{
// Use shift left to quickly multiply the X pos by 2 for double width lines.
const SHORT scale = IsDoubleWidthLine(position.Y) ? 1 : 0;
const auto scale = IsDoubleWidthLine(position.Y) ? 1 : 0;
return { position.X << scale, position.Y };
}
@@ -900,7 +896,7 @@ void TextBuffer::Reset()
// - newSize - new size of screen.
// Return Value:
// - Success if successful. Invalid parameter if screen buffer size is unexpected. No memory if allocation failed.
[[nodiscard]] NTSTATUS TextBuffer::ResizeTraditional(const COORD newSize) noexcept
[[nodiscard]] NTSTATUS TextBuffer::ResizeTraditional(const til::size newSize) noexcept
{
RETURN_HR_IF(E_INVALIDARG, newSize.X < 0 || newSize.Y < 0);
@@ -909,12 +905,12 @@ void TextBuffer::Reset()
const auto currentSize = GetSize().Dimensions();
const auto attributes = GetCurrentAttributes();
SHORT TopRow = 0; // new top row of the screen buffer
til::CoordType TopRow = 0; // new top row of the screen buffer
if (newSize.Y <= GetCursor().GetPosition().Y)
{
TopRow = GetCursor().GetPosition().Y - newSize.Y + 1;
}
const SHORT TopRowIndex = (GetFirstRowIndex() + TopRow) % currentSize.Y;
const auto TopRowIndex = (GetFirstRowIndex() + TopRow) % currentSize.Y;
// rotate rows until the top row is at index 0
for (auto i = 0; i < TopRowIndex; i++)
@@ -934,7 +930,7 @@ void TextBuffer::Reset()
// add rows if we're growing
while (_storage.size() < static_cast<size_t>(newSize.Y))
{
_storage.emplace_back(static_cast<short>(_storage.size()), newSize.X, attributes, this);
_storage.emplace_back(gsl::narrow_cast<til::CoordType>(_storage.size()), newSize.X, attributes, this);
}
// Now that we've tampered with the row placement, refresh all the row IDs.
@@ -983,7 +979,7 @@ void TextBuffer::TriggerRedraw(const Viewport& viewport)
}
}
void TextBuffer::TriggerRedrawCursor(const COORD position)
void TextBuffer::TriggerRedrawCursor(const til::point position)
{
if (_isActiveBuffer)
{
@@ -1007,7 +1003,7 @@ void TextBuffer::TriggerScroll()
}
}
void TextBuffer::TriggerScroll(const COORD delta)
void TextBuffer::TriggerScroll(const til::point delta)
{
if (_isActiveBuffer)
{
@@ -1032,10 +1028,10 @@ void TextBuffer::TriggerNewTextNotification(const std::wstring_view newText)
// any high unicode (UnicodeStorage) runs while we're already looping through the rows.
// Arguments:
// - newRowWidth - Optional new value for the row width.
void TextBuffer::_RefreshRowIDs(std::optional<SHORT> newRowWidth)
void TextBuffer::_RefreshRowIDs(std::optional<til::CoordType> newRowWidth)
{
std::unordered_map<SHORT, SHORT> rowMap;
SHORT i = 0;
std::unordered_map<til::CoordType, til::CoordType> rowMap;
til::CoordType i = 0;
for (auto& it : _storage)
{
// Build a map so we can update Unicode Storage
@@ -1065,7 +1061,7 @@ void TextBuffer::_RefreshRowIDs(std::optional<SHORT> newRowWidth)
// - <none>
// Return Value:
// - reference to the first row.
ROW& TextBuffer::_GetFirstRow()
ROW& TextBuffer::_GetFirstRow() noexcept
{
return GetRowByOffset(0);
}
@@ -1099,23 +1095,23 @@ ROW& TextBuffer::_GetPrevRowNoWrap(const ROW& Row)
// - wordDelimiters: the delimiters defined as a part of the DelimiterClass::DelimiterChar
// Return Value:
// - the delimiter class for the given char
const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const
DelimiterClass TextBuffer::_GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const
{
return GetRowByOffset(pos.Y).GetCharRow().DelimiterClassAt(pos.X, wordDelimiters);
}
// Method Description:
// - Get the COORD for the beginning of the word you are on
// - Get the til::point for the beginning of the word you are on
// Arguments:
// - target - a COORD on the word you are currently on
// - 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 COORD for the first character on the "word" (inclusive)
const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
// - 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 "
@@ -1130,7 +1126,7 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
#pragma warning(suppress : 26496)
auto copy{ target };
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (target == bufferSize.Origin())
{
// can't expand left
@@ -1140,12 +1136,12 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
{
// GH#7664: Treat EndExclusive as EndInclusive so
// that it actually points to a space in the buffer
copy = { bufferSize.RightInclusive(), bufferSize.BottomInclusive() };
copy = bufferSize.BottomRightInclusive();
}
else if (bufferSize.CompareInBounds(target, limit.to_win32_coord(), true) >= 0)
else if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
// if at/past the limit --> clamp to limit
copy = limitOptional->to_win32_coord();
copy = limitOptional.value_or(bufferSize.BottomRightInclusive());
}
if (accessibilityMode)
@@ -1159,13 +1155,13 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
}
// Method Description:
// - Helper method for GetWordStart(). Get the COORD for the beginning of the word (accessibility definition) you are on
// - Helper method for GetWordStart(). Get the til::point for the beginning of the word (accessibility definition) you are on
// Arguments:
// - target - a COORD on the word you are currently on
// - 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 COORD for the first character on the current/previous READABLE "word" (inclusive)
const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const
// - 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();
@@ -1204,13 +1200,13 @@ const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const
}
// Method Description:
// - Helper method for GetWordStart(). Get the COORD for the beginning of the word (selection definition) you are on
// - Helper method for GetWordStart(). Get the til::point for the beginning of the word (selection definition) you are on
// Arguments:
// - target - a COORD on the word you are currently on
// - 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 COORD for the first character on the current word or delimiter run (stopped by the left margin)
const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const
// - 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();
@@ -1233,17 +1229,17 @@ const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std:
}
// Method Description:
// - Get the COORD for the beginning of the NEXT word
// - Get the til::point for the beginning of the NEXT word
// Arguments:
// - target - a COORD on the word you are currently on
// - 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 COORD for the last character on the "word" (inclusive)
const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
// - 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 "
@@ -1257,15 +1253,15 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w
// Already at/past the limit. Can't move forward.
const auto bufferSize{ GetSize() };
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
if (bufferSize.CompareInBounds(target, limit.to_win32_coord(), true) >= 0)
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
{
return target;
}
if (accessibilityMode)
{
return _GetWordEndForAccessibility(target, wordDelimiters, limit.to_win32_coord());
return _GetWordEndForAccessibility(target, wordDelimiters, limit);
}
else
{
@@ -1274,14 +1270,14 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w
}
// Method Description:
// - Helper method for GetWordEnd(). Get the COORD for the beginning of the next READABLE word
// - Helper method for GetWordEnd(). Get the til::point for the beginning of the next READABLE word
// Arguments:
// - target - a COORD on the word you are currently on
// - 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 COORD for the first character of the next readable "word". If no next word, return one past the end of the buffer
const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD limit) const
// - 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 };
@@ -1325,13 +1321,13 @@ const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const st
}
// Method Description:
// - Helper method for GetWordEnd(). Get the COORD for the beginning of the NEXT word
// - Helper method for GetWordEnd(). Get the til::point for the beginning of the NEXT word
// Arguments:
// - target - a COORD on the word you are currently on
// - 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 COORD for the last character of the current word or delimiter run (stopped by right margin)
const COORD TextBuffer::_GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const
// - 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();
@@ -1380,7 +1376,7 @@ void TextBuffer::_PruneHyperlinks()
// we have found all hyperlink references in the first row and put them in refs,
// now we need to search the rest of the buffer (i.e. all the rows except the first)
// to see if those references are anywhere else
for (size_t i = 1; i != total; ++i)
for (til::CoordType i = 1; i < total; ++i)
{
const auto nextRowRefs = GetRowByOffset(i).GetAttrRow().GetHyperlinks();
for (auto id : nextRowRefs)
@@ -1408,22 +1404,22 @@ 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 COORD on the word you are currently on
// - 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 COORD for the first character on the "word" (inclusive)
bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional) const
// - 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(til::point{ bufferSize.EndExclusive() }) };
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit.to_win32_coord()) };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) };
if (bufferSize.CompareInBounds(copy, limit.to_win32_coord(), true) >= 0)
if (bufferSize.CompareInBounds(copy, limit, true) >= 0)
{
return false;
}
@@ -1435,12 +1431,12 @@ bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimite
// Method Description:
// - Update pos to be the position of the first character of the previous word. This is used for accessibility
// Arguments:
// - pos - a COORD on the word you are currently on
// - 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 COORD for the first character on the "word" (inclusive)
bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters) const
// - 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) };
@@ -1459,51 +1455,51 @@ bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters
// Method Description:
// - Update pos to be the beginning of the current glyph/character. This is used for accessibility
// Arguments:
// - pos - a COORD on the word you are currently on
// - pos - a til::point on the word you are currently on
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value:
// - pos - The COORD for the first cell of the current glyph (inclusive)
const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional) const
// - pos - The til::point for the first cell of the current glyph (inclusive)
til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional) const
{
auto resultPos = pos.to_win32_coord();
auto resultPos = pos;
const auto bufferSize = GetSize();
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
// Clamp pos to limit
if (bufferSize.CompareInBounds(resultPos, limit.to_win32_coord(), true) > 0)
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
{
resultPos = limit.to_win32_coord();
resultPos = limit;
}
// limit is exclusive, so we need to move back to be within valid bounds
if (resultPos != limit.to_win32_coord() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
{
bufferSize.DecrementInBounds(resultPos, true);
}
return til::point{ resultPos };
return resultPos;
}
// Method Description:
// - Update pos to be the end of the current glyph/character.
// Arguments:
// - pos - a COORD on the word you are currently on
// - pos - a til::point on the word you are currently on
// - accessibilityMode - this is being used for accessibility; make the end exclusive.
// Return Value:
// - pos - The COORD for the last cell of the current glyph (exclusive)
const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode, std::optional<til::point> limitOptional) const
// - pos - The til::point for the last cell of the current glyph (exclusive)
til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode, std::optional<til::point> limitOptional) const
{
auto resultPos = pos.to_win32_coord();
auto resultPos = pos;
const auto bufferSize = GetSize();
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
// Clamp pos to limit
if (bufferSize.CompareInBounds(resultPos, limit.to_win32_coord(), true) > 0)
if (bufferSize.CompareInBounds(resultPos, limit, true) > 0)
{
resultPos = limit.to_win32_coord();
resultPos = limit;
}
if (resultPos != limit.to_win32_coord() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
{
bufferSize.IncrementInBounds(resultPos, true);
}
@@ -1513,24 +1509,24 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilit
{
bufferSize.IncrementInBounds(resultPos, true);
}
return til::point{ resultPos };
return resultPos;
}
// Method Description:
// - Update pos to be the beginning of the next glyph/character. This is used for accessibility
// Arguments:
// - pos - a COORD on the word you are currently on
// - pos - a til::point on the word you are currently on
// - allowExclusiveEnd - allow result to be the exclusive limit (one past limit)
// - limit - boundaries for the iterator to operate within
// Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The COORD for the first cell of the current glyph (inclusive)
// - pos - The til::point for the first cell of the current glyph (inclusive)
bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::optional<til::point> limitOptional) const
{
const auto bufferSize = GetSize();
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
const auto distanceToLimit{ bufferSize.CompareInBounds(pos.to_win32_coord(), limit.to_win32_coord(), true) };
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit, true) };
if (distanceToLimit >= 0)
{
// Corner Case: we're on/past the limit
@@ -1547,7 +1543,7 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o
}
// Try to move forward, but if we hit the buffer boundary, we fail to move.
auto iter{ GetCellDataAt(pos.to_win32_coord(), bufferSize) };
auto iter{ GetCellDataAt(pos, bufferSize) };
const bool success{ ++iter };
// Move again if we're on a wide glyph
@@ -1556,24 +1552,24 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o
++iter;
}
pos = til::point{ iter.Pos() };
pos = iter.Pos();
return success;
}
// Method Description:
// - Update pos to be the beginning of the previous glyph/character. This is used for accessibility
// Arguments:
// - pos - a COORD on the word you are currently on
// - pos - a til::point on the word you are currently on
// Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The COORD for the first cell of the previous glyph (inclusive)
// - pos - The til::point for the first cell of the previous glyph (inclusive)
bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point> limitOptional) const
{
auto resultPos = pos.to_win32_coord();
auto resultPos = pos;
const auto bufferSize = GetSize();
const auto limit{ limitOptional.value_or(til::point{ bufferSize.EndExclusive() }) };
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
if (bufferSize.CompareInBounds(pos.to_win32_coord(), limit.to_win32_coord(), true) > 0)
if (bufferSize.CompareInBounds(pos, limit, true) > 0)
{
// we're past the end
// clamp us to the limit
@@ -1588,7 +1584,7 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point>
bufferSize.DecrementInBounds(resultPos, true);
}
pos = til::point{ resultPos };
pos = resultPos;
return success;
}
@@ -1606,9 +1602,9 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point>
// the buffer rather than the screen.
// Return Value:
// - the delimiter class for the given char
const std::vector<SMALL_RECT> TextBuffer::GetTextRects(COORD start, COORD end, bool blockSelection, bool bufferCoordinates) const
const std::vector<til::inclusive_rect> TextBuffer::GetTextRects(til::point start, til::point end, bool blockSelection, bool bufferCoordinates) const
{
std::vector<SMALL_RECT> textRects;
std::vector<til::inclusive_rect> textRects;
const auto bufferSize = GetSize();
@@ -1619,11 +1615,11 @@ const std::vector<SMALL_RECT> TextBuffer::GetTextRects(COORD start, COORD end, b
std::make_tuple(start, end) :
std::make_tuple(end, start);
const auto textRectSize = base::ClampedNumeric<short>(1) + lowerCoord.Y - higherCoord.Y;
const auto textRectSize = 1 + lowerCoord.Y - higherCoord.Y;
textRects.reserve(textRectSize);
for (auto row = higherCoord.Y; row <= lowerCoord.Y; row++)
{
SMALL_RECT textRow;
til::inclusive_rect textRow;
textRow.Top = row;
textRow.Bottom = row;
@@ -1661,12 +1657,12 @@ const std::vector<SMALL_RECT> TextBuffer::GetTextRects(COORD start, COORD end, b
// - selectionRow: the selection row to be expanded
// Return Value:
// - modifies selectionRow's Left and Right values to expand properly
void TextBuffer::_ExpandTextRow(SMALL_RECT& textRow) const
void TextBuffer::_ExpandTextRow(til::inclusive_rect& textRow) const
{
const auto bufferSize = GetSize();
// expand left side of rect
COORD targetPoint{ textRow.Left, textRow.Top };
til::point targetPoint{ textRow.Left, textRow.Top };
if (GetCellDataAt(targetPoint)->DbcsAttr().IsTrailing())
{
if (targetPoint.X == bufferSize.Left())
@@ -1708,7 +1704,7 @@ void TextBuffer::_ExpandTextRow(SMALL_RECT& textRow) const
// - The text, background color, and foreground color data of the selected region of the text buffer.
const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
const bool trimTrailingWhitespace,
const std::vector<SMALL_RECT>& selectionRects,
const std::vector<til::inclusive_rect>& selectionRects,
std::function<std::pair<COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors,
const bool formatWrappedRows) const
{
@@ -1725,9 +1721,9 @@ const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
}
// for each row in the selection
for (UINT i = 0; i < rows; i++)
for (size_t i = 0; i < rows; i++)
{
const UINT iRow = selectionRects.at(i).Top;
const auto iRow = selectionRects.at(i).Top;
const auto highlight = Viewport::FromInclusive(selectionRects.at(i));
@@ -2243,22 +2239,22 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
const auto cOldCursorPos = oldCursor.GetPosition();
const auto cOldLastChar = oldBuffer.GetLastNonSpaceCharacter(lastCharacterViewport);
const short cOldRowsTotal = cOldLastChar.Y + 1;
const auto cOldRowsTotal = cOldLastChar.Y + 1;
COORD cNewCursorPos = { 0 };
til::point cNewCursorPos;
auto fFoundCursorPos = false;
auto foundOldMutable = false;
auto foundOldVisible = false;
auto hr = S_OK;
// Loop through all the rows of the old buffer and reprint them into the new buffer
short iOldRow = 0;
til::CoordType iOldRow = 0;
for (; iOldRow < cOldRowsTotal; iOldRow++)
{
// Fetch the row and its "right" which is the last printable character.
const auto& row = oldBuffer.GetRowByOffset(iOldRow);
const auto cOldColsTotal = oldBuffer.GetLineWidth(iOldRow);
const auto& charRow = row.GetCharRow();
auto iRight = gsl::narrow_cast<short>(charRow.MeasureRight());
auto iRight = charRow.MeasureRight();
// If we're starting a new row, try and preserve the line rendition
// from the row in the original buffer.
@@ -2296,7 +2292,7 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
// Loop through every character in the current row (up to
// the "right" boundary, which is one past the final valid
// character)
short iOldCol = 0;
til::CoordType iOldCol = 0;
const auto copyRight = iRight;
for (; iOldCol < copyRight; iOldCol++)
{
@@ -2439,7 +2435,7 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
const auto coordNewCursor = newCursor.GetPosition();
if (coordNewCursor.X == 0 && coordNewCursor.Y > 0)
{
if (newBuffer.GetRowByOffset(gsl::narrow_cast<size_t>(coordNewCursor.Y) - 1).WasWrapForced())
if (newBuffer.GetRowByOffset(coordNewCursor.Y - 1).WasWrapForced())
{
hr = newBuffer.NewlineCursor() ? hr : E_OUTOFMEMORY;
}
@@ -2693,17 +2689,17 @@ void TextBuffer::CopyPatterns(const TextBuffer& OtherBuffer)
// - The lastRow to search
// Return value:
// - An interval tree containing the patterns found
PointTree TextBuffer::GetPatterns(const size_t firstRow, const size_t lastRow) const
PointTree TextBuffer::GetPatterns(const til::CoordType firstRow, const til::CoordType lastRow) const
{
PointTree::interval_vector intervals;
std::wstring concatAll;
const auto rowSize = GetRowByOffset(0).size();
concatAll.reserve(rowSize * (lastRow - firstRow + 1));
concatAll.reserve(gsl::narrow_cast<size_t>(rowSize) * gsl::narrow_cast<size_t>(lastRow - firstRow + 1));
// to deal with text that spans multiple lines, we will first concatenate
// all the text into one string and find the patterns in that string
for (auto i = firstRow; i <= lastRow; ++i)
for (til::CoordType i = firstRow; i <= lastRow; ++i)
{
auto& row = GetRowByOffset(i);
concatAll += row.GetText();
@@ -2718,21 +2714,21 @@ PointTree TextBuffer::GetPatterns(const size_t firstRow, const size_t lastRow) c
auto words_begin = std::wsregex_iterator(concatAll.begin(), concatAll.end(), regexObj);
auto words_end = std::wsregex_iterator();
size_t lenUpToThis = 0;
til::CoordType lenUpToThis = 0;
for (auto i = words_begin; i != words_end; ++i)
{
// record the locations -
// when we find a match, the prefix is text that is between this
// match and the previous match, so we use the size of the prefix
// along with the size of the match to determine the locations
size_t prefixSize = 0;
til::CoordType prefixSize = 0;
for (const auto parsedGlyph : Utf16Parser::Parse(i->prefix().str()))
{
const std::wstring_view glyph{ parsedGlyph.data(), parsedGlyph.size() };
prefixSize += IsGlyphFullWidth(glyph) ? 2 : 1;
}
const auto start = lenUpToThis + prefixSize;
size_t matchSize = 0;
til::CoordType matchSize = 0;
for (const auto parsedGlyph : Utf16Parser::Parse(i->str()))
{
const std::wstring_view glyph{ parsedGlyph.data(), parsedGlyph.size() };
@@ -2741,8 +2737,8 @@ PointTree TextBuffer::GetPatterns(const size_t firstRow, const size_t lastRow) c
const auto end = start + matchSize;
lenUpToThis = end;
const til::point startCoord{ gsl::narrow<SHORT>(start % rowSize), gsl::narrow<SHORT>(start / rowSize) };
const til::point endCoord{ gsl::narrow<SHORT>(end % rowSize), gsl::narrow<SHORT>(end / rowSize) };
const til::point startCoord{ start % rowSize, start / rowSize };
const til::point endCoord{ end % rowSize, end / rowSize };
// store the intervals
// NOTE: these intervals are relative to the VIEWPORT not the buffer

View File

@@ -68,7 +68,7 @@ namespace Microsoft::Console::Render
class TextBuffer final
{
public:
TextBuffer(const COORD screenBufferSize,
TextBuffer(const til::size screenBufferSize,
const TextAttribute defaultAttributes,
const UINT cursorSize,
const bool isActiveBuffer,
@@ -79,27 +79,27 @@ public:
void CopyProperties(const TextBuffer& OtherBuffer) noexcept;
// row manipulation
const ROW& GetRowByOffset(const size_t index) const;
ROW& GetRowByOffset(const size_t index);
const ROW& GetRowByOffset(const til::CoordType index) const noexcept;
ROW& GetRowByOffset(const til::CoordType index) noexcept;
TextBufferCellIterator GetCellDataAt(const COORD at) const;
TextBufferCellIterator GetCellLineDataAt(const COORD at) const;
TextBufferCellIterator GetCellDataAt(const COORD at, const Microsoft::Console::Types::Viewport limit) const;
TextBufferTextIterator GetTextDataAt(const COORD at) const;
TextBufferTextIterator GetTextLineDataAt(const COORD at) const;
TextBufferTextIterator GetTextDataAt(const COORD at, const Microsoft::Console::Types::Viewport limit) const;
TextBufferCellIterator GetCellDataAt(const til::point at) const;
TextBufferCellIterator GetCellLineDataAt(const til::point at) const;
TextBufferCellIterator GetCellDataAt(const til::point at, const Microsoft::Console::Types::Viewport limit) const;
TextBufferTextIterator GetTextDataAt(const til::point at) const;
TextBufferTextIterator GetTextLineDataAt(const til::point at) const;
TextBufferTextIterator GetTextDataAt(const til::point at, const Microsoft::Console::Types::Viewport limit) const;
// Text insertion functions
OutputCellIterator Write(const OutputCellIterator givenIt);
OutputCellIterator Write(const OutputCellIterator givenIt,
const COORD target,
const til::point target,
const std::optional<bool> wrap = true);
OutputCellIterator WriteLine(const OutputCellIterator givenIt,
const COORD target,
const til::point target,
const std::optional<bool> setWrap = std::nullopt,
const std::optional<size_t> limitRight = std::nullopt);
const std::optional<til::CoordType> limitRight = std::nullopt);
bool InsertCharacter(const wchar_t wch, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
bool InsertCharacter(const std::wstring_view chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
@@ -109,36 +109,36 @@ public:
// Scroll needs access to this to quickly rotate around the buffer.
bool IncrementCircularBuffer(const bool inVtMode = false);
COORD GetLastNonSpaceCharacter(std::optional<const Microsoft::Console::Types::Viewport> viewOptional = std::nullopt) const;
til::point GetLastNonSpaceCharacter(std::optional<const Microsoft::Console::Types::Viewport> viewOptional = std::nullopt) const;
Cursor& GetCursor() noexcept;
const Cursor& GetCursor() const noexcept;
const SHORT GetFirstRowIndex() const noexcept;
const til::CoordType GetFirstRowIndex() const noexcept;
const Microsoft::Console::Types::Viewport GetSize() const noexcept;
void ScrollRows(const SHORT firstRow, const SHORT size, const SHORT delta);
void ScrollRows(const til::CoordType firstRow, const til::CoordType size, const til::CoordType delta);
UINT TotalRowCount() const noexcept;
til::CoordType TotalRowCount() const noexcept;
[[nodiscard]] TextAttribute GetCurrentAttributes() const noexcept;
void SetCurrentAttributes(const TextAttribute& currentAttributes) noexcept;
void SetCurrentLineRendition(const LineRendition lineRendition);
void ResetLineRenditionRange(const size_t startRow, const size_t endRow);
LineRendition GetLineRendition(const size_t row) const;
bool IsDoubleWidthLine(const size_t row) const;
void ResetLineRenditionRange(const til::CoordType startRow, const til::CoordType endRow) noexcept;
LineRendition GetLineRendition(const til::CoordType row) const noexcept;
bool IsDoubleWidthLine(const til::CoordType row) const noexcept;
SHORT GetLineWidth(const size_t row) const;
COORD ClampPositionWithinLine(const COORD position) const;
COORD ScreenToBufferPosition(const COORD position) const;
COORD BufferToScreenPosition(const COORD position) const;
til::CoordType GetLineWidth(const til::CoordType row) const noexcept;
til::point ClampPositionWithinLine(const til::point position) const noexcept;
til::point ScreenToBufferPosition(const til::point position) const noexcept;
til::point BufferToScreenPosition(const til::point position) const noexcept;
void Reset();
[[nodiscard]] HRESULT ResizeTraditional(const COORD newSize) noexcept;
[[nodiscard]] HRESULT ResizeTraditional(const til::size newSize) noexcept;
const UnicodeStorage& GetUnicodeStorage() const noexcept;
UnicodeStorage& GetUnicodeStorage() noexcept;
@@ -149,23 +149,23 @@ public:
Microsoft::Console::Render::Renderer& GetRenderer() noexcept;
void TriggerRedraw(const Microsoft::Console::Types::Viewport& viewport);
void TriggerRedrawCursor(const COORD position);
void TriggerRedrawCursor(const til::point position);
void TriggerRedrawAll();
void TriggerScroll();
void TriggerScroll(const COORD delta);
void TriggerScroll(const til::point delta);
void TriggerNewTextNotification(const std::wstring_view newText);
const COORD GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
const COORD GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToPreviousWord(COORD& pos, const std::wstring_view wordDelimiters) const;
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;
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;
const til::point GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional = std::nullopt) const;
const til::point GetGlyphEnd(const til::point pos, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) 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;
bool MoveToNextGlyph(til::point& pos, bool allowBottomExclusive = false, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToPreviousGlyph(til::point& pos, std::optional<til::point> limitOptional = std::nullopt) const;
const std::vector<SMALL_RECT> GetTextRects(COORD start, COORD end, bool blockSelection, bool bufferCoordinates) const;
const std::vector<til::inclusive_rect> GetTextRects(til::point start, til::point end, bool blockSelection, bool bufferCoordinates) const;
void AddHyperlinkToMap(std::wstring_view uri, uint16_t id);
std::wstring GetHyperlinkUriFromId(uint16_t id) const;
@@ -184,7 +184,7 @@ public:
const TextAndColor GetText(const bool includeCRLF,
const bool trimTrailingWhitespace,
const std::vector<SMALL_RECT>& textRects,
const std::vector<til::inclusive_rect>& textRects,
std::function<std::pair<COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors = nullptr,
const bool formatWrappedRows = false) const;
@@ -200,8 +200,8 @@ public:
struct PositionInformation
{
short mutableViewportTop{ 0 };
short visibleViewportTop{ 0 };
til::CoordType mutableViewportTop{ 0 };
til::CoordType visibleViewportTop{ 0 };
};
static HRESULT Reflow(TextBuffer& oldBuffer,
@@ -212,7 +212,7 @@ public:
const size_t AddPatternRecognizer(const std::wstring_view regexString);
void ClearPatternRecognizers() noexcept;
void CopyPatterns(const TextBuffer& OtherBuffer);
interval_tree::IntervalTree<til::point, size_t> GetPatterns(const size_t firstRow, const size_t lastRow) const;
interval_tree::IntervalTree<til::point, size_t> GetPatterns(const til::CoordType firstRow, const til::CoordType lastRow) const;
private:
void _UpdateSize();
@@ -220,7 +220,7 @@ private:
std::vector<ROW> _storage;
Cursor _cursor;
SHORT _firstRow; // indexes top row (not necessarily 0)
til::CoordType _firstRow; // indexes top row (not necessarily 0)
TextAttribute _currentAttributes;
@@ -234,29 +234,29 @@ private:
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
uint16_t _currentHyperlinkId;
void _RefreshRowIDs(std::optional<SHORT> newRowWidth);
void _RefreshRowIDs(std::optional<til::CoordType> newRowWidth);
void _SetFirstRowIndex(const SHORT FirstRowIndex) noexcept;
void _SetFirstRowIndex(const til::CoordType FirstRowIndex) noexcept;
COORD _GetPreviousFromCursor() const;
til::point _GetPreviousFromCursor() const noexcept;
void _SetWrapOnCurrentRow();
void _AdjustWrapOnCurrentRow(const bool fSet);
void _SetWrapOnCurrentRow() noexcept;
void _AdjustWrapOnCurrentRow(const bool fSet) noexcept;
// Assist with maintaining proper buffer state for Double Byte character sequences
bool _PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute);
bool _AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribute);
ROW& _GetFirstRow();
ROW& _GetFirstRow() noexcept;
ROW& _GetPrevRowNoWrap(const ROW& row);
void _ExpandTextRow(SMALL_RECT& selectionRow) const;
void _ExpandTextRow(til::inclusive_rect& selectionRow) const;
const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const;
const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const;
const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD limit) const;
const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
DelimiterClass _GetDelimiterClassAt(const 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;
void _PruneHyperlinks();

View File

@@ -19,7 +19,7 @@ using namespace Microsoft::Console::Types;
// Arguments:
// - buffer - Text buffer to seek through
// - pos - Starting position to retrieve text data from (within screen buffer bounds)
TextBufferCellIterator::TextBufferCellIterator(const TextBuffer& buffer, COORD pos) :
TextBufferCellIterator::TextBufferCellIterator(const TextBuffer& buffer, til::point pos) :
TextBufferCellIterator(buffer, pos, buffer.GetSize())
{
}
@@ -30,7 +30,7 @@ TextBufferCellIterator::TextBufferCellIterator(const TextBuffer& buffer, COORD p
// - buffer - Pointer to screen buffer to seek through
// - pos - Starting position to retrieve text data from (within screen buffer bounds)
// - limits - Viewport limits to restrict the iterator within the buffer bounds (smaller than the buffer itself)
TextBufferCellIterator::TextBufferCellIterator(const TextBuffer& buffer, COORD pos, const Viewport limits) :
TextBufferCellIterator::TextBufferCellIterator(const TextBuffer& buffer, til::point pos, const Viewport limits) :
_buffer(buffer),
_pos(pos),
_pRow(s_GetRow(buffer, pos)),
@@ -126,7 +126,7 @@ TextBufferCellIterator& TextBufferCellIterator::operator+=(const ptrdiff_t& move
const auto oldX = _pos.X;
const auto oldY = _pos.Y;
// Under MSVC writing the individual members of a COORD generates worse assembly
// Under MSVC writing the individual members of a til::point generates worse assembly
// compared to having them be local variables. This causes a performance impact.
auto newX = oldX;
auto newY = oldY;
@@ -289,7 +289,7 @@ ptrdiff_t TextBufferCellIterator::operator-(const TextBufferCellIterator& it)
// - Sets the coordinate position that this iterator will inspect within the text buffer on dereference.
// Arguments:
// - newPos - The new coordinate position.
void TextBufferCellIterator::_SetPos(const COORD newPos)
void TextBufferCellIterator::_SetPos(const til::point newPos)
{
if (newPos.Y != _pos.Y)
{
@@ -317,7 +317,7 @@ void TextBufferCellIterator::_SetPos(const COORD newPos)
// - pos - Position inside screen buffer bounds to retrieve row
// Return Value:
// - Pointer to the underlying CharRow structure
const ROW* TextBufferCellIterator::s_GetRow(const TextBuffer& buffer, const COORD pos)
const ROW* TextBufferCellIterator::s_GetRow(const TextBuffer& buffer, const til::point pos) noexcept
{
return &buffer.GetRowByOffset(pos.Y);
}
@@ -354,7 +354,7 @@ const OutputCellView* TextBufferCellIterator::operator->() const noexcept
return &_view;
}
COORD TextBufferCellIterator::Pos() const noexcept
til::point TextBufferCellIterator::Pos() const noexcept
{
return _pos;
}

View File

@@ -25,8 +25,8 @@ class TextBuffer;
class TextBufferCellIterator
{
public:
TextBufferCellIterator(const TextBuffer& buffer, COORD pos);
TextBufferCellIterator(const TextBuffer& buffer, COORD pos, const Microsoft::Console::Types::Viewport limits);
TextBufferCellIterator(const TextBuffer& buffer, til::point pos);
TextBufferCellIterator(const TextBuffer& buffer, til::point pos, const Microsoft::Console::Types::Viewport limits);
operator bool() const noexcept;
@@ -47,12 +47,12 @@ public:
const OutputCellView& operator*() const noexcept;
const OutputCellView* operator->() const noexcept;
COORD Pos() const noexcept;
til::point Pos() const noexcept;
protected:
void _SetPos(const COORD newPos);
void _SetPos(const til::point newPos);
void _GenerateView();
static const ROW* s_GetRow(const TextBuffer& buffer, const COORD pos);
static const ROW* s_GetRow(const TextBuffer& buffer, const til::point pos) noexcept;
OutputCellView _view;
@@ -61,7 +61,7 @@ protected:
const TextBuffer& _buffer;
const Microsoft::Console::Types::Viewport _bounds;
bool _exceeded;
COORD _pos;
til::point _pos;
#if UNIT_TESTING
friend class TextBufferIteratorTests;

View File

@@ -36,9 +36,9 @@ namespace
struct TestBuffer
{
COORD size;
til::size size;
std::vector<TestRow> rows;
COORD cursor;
til::point cursor;
};
struct TestCase
@@ -737,7 +737,7 @@ class ReflowTests
{
auto buffer = std::make_unique<TextBuffer>(testBuffer.size, TextAttribute{ 0x7 }, 0, false, renderer);
size_t i{};
til::CoordType i{};
for (const auto& testRow : testBuffer.rows)
{
auto& row{ buffer->GetRowByOffset(i) };
@@ -745,7 +745,7 @@ class ReflowTests
auto& charRow{ row.GetCharRow() };
row.SetWrapForced(testRow.wrap);
size_t j{};
til::CoordType j{};
for (auto it{ charRow.begin() }; it != charRow.end(); ++it)
{
// Yes, we're about to manually create a buffer. It is unpleasant.
@@ -771,7 +771,7 @@ class ReflowTests
return buffer;
}
static std::unique_ptr<TextBuffer> _textBufferByReflowingTextBuffer(TextBuffer& originalBuffer, const COORD newSize)
static std::unique_ptr<TextBuffer> _textBufferByReflowingTextBuffer(TextBuffer& originalBuffer, const til::size newSize)
{
auto buffer = std::make_unique<TextBuffer>(newSize, TextAttribute{ 0x7 }, 0, false, renderer);
TextBuffer::Reflow(originalBuffer, *buffer, std::nullopt, std::nullopt);
@@ -783,7 +783,7 @@ class ReflowTests
VERIFY_ARE_EQUAL(testBuffer.cursor, buffer.GetCursor().GetPosition());
VERIFY_ARE_EQUAL(testBuffer.size, buffer.GetSize().Dimensions());
size_t i{};
til::CoordType i{};
for (const auto& testRow : testBuffer.rows)
{
NoThrowString indexString;
@@ -794,7 +794,7 @@ class ReflowTests
indexString.Format(L"[Row %d]", i);
VERIFY_ARE_EQUAL(testRow.wrap, row.WasWrapForced(), indexString);
size_t j{};
til::CoordType j{};
for (auto it{ charRow.begin() }; it != charRow.end(); ++it)
{
indexString.Format(L"[Cell %d, %d; Text line index %d]", it - charRow.begin(), i, j);

View File

@@ -18,7 +18,7 @@ class UnicodeStorageTests
TEST_METHOD(CanOverwriteEmoji)
{
UnicodeStorage storage;
const COORD coord{ 1, 3 };
const til::point coord{ 1, 3 };
const std::vector<wchar_t> newMoon{ 0xD83C, 0xDF11 };
const std::vector<wchar_t> fullMoon{ 0xD83C, 0xDF15 };

View File

@@ -37,7 +37,6 @@ Abstract:
// private dependencies
#include "../host/conddkrefs.h"
#include "../inc/operators.hpp"
#include "../inc/unicode.hpp"
#pragma warning(pop)

View File

@@ -1,12 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<PropertyGroup Label="NuGet Dependencies">
<TerminalMUX>true</TerminalMUX>
</PropertyGroup>
<Import Project="$(OpenConsoleDir)src\wap-common.build.pre.props" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<PropertyGroup Label="Configuration">
<!--
These two properties are very important!
@@ -140,10 +135,6 @@
<!-- 16.3.0 - remove non-resources.pri PRI files since we just forced them back in. -->
<AppxPackagePayload Remove="@(AppxPackagePayload)" Condition="'%(Extension)' == '.pri' and '%(Filename)' != 'resources'" />
<AppxUploadPackagePayload Remove="@(AppxUploadPackagePayload)" Condition="'%(Extension)' == '.pri' and '%(Filename)' != 'resources'" />
<!-- Remove all of the xaml files, because we are using embedded xbf payloads (saves about 500kb on disk!) -->
<AppxPackagePayload Remove="@(AppxPackagePayload)" Condition="'%(Extension)' == '.xaml'" />
<AppxUploadPackagePayload Remove="@(AppxUploadPackagePayload)" Condition="'%(Extension)' == '.xaml'" />
</ItemGroup>
</Target>
@@ -169,7 +160,13 @@
</Target>
<!-- This is required to get the package dependency in the AppXManifest. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project>

View File

@@ -100,6 +100,7 @@
<com:ProxyStub Id="DEC4804D-56D1-4F73-9FBE-6828E7C85C56" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="DEC4804D-56D1-4F73-9FBE-6828E7C85C56"/>
</com:ComInterface>
</com:Extension>
<com:Extension Category="windows.comServer">

View File

@@ -189,6 +189,7 @@
<com:ProxyStub Id="1833E661-CC81-4DD0-87C6-C2F74BD39EFA" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/>
</com:ComInterface>
</com:Extension>
<com:Extension Category="windows.comServer">

View File

@@ -189,6 +189,7 @@
<com:ProxyStub Id="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
</com:ComInterface>
</com:Extension>
<com:Extension Category="windows.comServer">

View File

@@ -230,7 +230,7 @@ HRESULT HwndTerminal::Initialize()
RECT windowRect;
GetWindowRect(_hwnd.get(), &windowRect);
const COORD windowSize{ gsl::narrow<short>(windowRect.right - windowRect.left), gsl::narrow<short>(windowRect.bottom - windowRect.top) };
const til::size windowSize{ windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
// Fist set up the dx engine with the window size in pixels.
// Then, using the font, get the number of characters that can fit.
@@ -239,7 +239,7 @@ HRESULT HwndTerminal::Initialize()
_renderEngine = std::move(dxEngine);
_terminal->Create(COORD{ 80, 25 }, 1000, *_renderer);
_terminal->Create({ 80, 25 }, 1000, *_renderer);
_terminal->SetWriteInputCallback([=](std::wstring_view input) noexcept { _WriteTextToConnection(input); });
localPointerToThread->EnablePainting();
@@ -343,7 +343,7 @@ IRawElementProviderSimple* HwndTerminal::_GetUiaProvider() noexcept
return _uiaProvider.Get();
}
HRESULT HwndTerminal::Refresh(const SIZE windowSize, _Out_ COORD* dimensions)
HRESULT HwndTerminal::Refresh(const til::size windowSize, _Out_ til::size* dimensions)
{
RETURN_HR_IF_NULL(E_INVALIDARG, dimensions);
@@ -357,8 +357,7 @@ HRESULT HwndTerminal::Refresh(const SIZE windowSize, _Out_ COORD* dimensions)
_renderer->TriggerRedrawAll();
// Convert our new dimensions to characters
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 },
{ gsl::narrow<short>(windowSize.cx), gsl::narrow<short>(windowSize.cy) });
const auto viewInPixels = Viewport::FromDimensions(windowSize);
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
// If this function succeeds with S_FALSE, then the terminal didn't
@@ -435,7 +434,7 @@ void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data)
/// <param name="height">New height of the terminal in pixels</param>
/// <param name="dimensions">Out parameter containing the columns and rows that fit the new size.</param>
/// <returns>HRESULT of the attempted resize.</returns>
HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions)
HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ til::CoordType width, _In_ til::CoordType height, _Out_ til::size* dimensions)
{
const auto publicTerminal = static_cast<HwndTerminal*>(terminal);
@@ -448,7 +447,7 @@ HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ short width, _I
static_cast<int>(height),
0));
const SIZE windowSize{ width, height };
const til::size windowSize{ width, height };
return publicTerminal->Refresh(windowSize, dimensions);
}
@@ -459,19 +458,19 @@ HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ short width, _I
/// <param name="dimensionsInCharacters">New terminal size in row and column count.</param>
/// <param name="dimensionsInPixels">Out parameter with the new size of the renderer.</param>
/// <returns>HRESULT of the attempted resize.</returns>
HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ COORD dimensionsInCharacters, _Out_ SIZE* dimensionsInPixels)
HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ til::size dimensionsInCharacters, _Out_ til::size* dimensionsInPixels)
{
RETURN_HR_IF_NULL(E_INVALIDARG, dimensionsInPixels);
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
const auto viewInCharacters = Viewport::FromDimensions({ 0, 0 }, { (dimensionsInCharacters.X), (dimensionsInCharacters.Y) });
const auto viewInCharacters = Viewport::FromDimensions(dimensionsInCharacters);
const auto viewInPixels = publicTerminal->_renderEngine->GetViewportInPixels(viewInCharacters);
dimensionsInPixels->cx = viewInPixels.Width();
dimensionsInPixels->cy = viewInPixels.Height();
COORD unused{ 0, 0 };
til::size unused;
return TerminalTriggerResize(terminal, viewInPixels.Width(), viewInPixels.Height(), &unused);
}
@@ -484,7 +483,7 @@ HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ CO
/// <param name="height">Height of the terminal area to calculate.</param>
/// <param name="dimensions">Out parameter containing the columns and rows that fit the new size.</param>
/// <returns>HRESULT of the calculation.</returns>
HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions)
HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ til::CoordType width, _In_ til::CoordType height, _Out_ til::size* dimensions)
{
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
@@ -548,11 +547,11 @@ try
if (multiClickMapper == 3)
{
_terminal->MultiClickSelection((cursorPosition / fontSize).to_win32_coord(), ::Terminal::SelectionExpansion::Line);
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Line);
}
else if (multiClickMapper == 2)
{
_terminal->MultiClickSelection((cursorPosition / fontSize).to_win32_coord(), ::Terminal::SelectionExpansion::Word);
_terminal->MultiClickSelection(cursorPosition / fontSize, ::Terminal::SelectionExpansion::Word);
}
else
{
@@ -593,13 +592,13 @@ try
if (distanceSquared >= maxDistanceSquared)
{
_terminal->SetSelectionAnchor((touchdownPoint / fontSize).to_win32_coord());
_terminal->SetSelectionAnchor(touchdownPoint / fontSize);
// stop tracking the touchdown point
_singleClickTouchdownPos = std::nullopt;
}
}
this->_terminal->SetSelectionEnd((cursorPosition / fontSize).to_win32_coord());
this->_terminal->SetSelectionEnd(cursorPosition / fontSize);
this->_renderer->TriggerSelection();
return S_OK;
@@ -701,9 +700,7 @@ try
wheelDelta = HIWORD(wParam);
// If it's a *WHEEL event, it's in screen coordinates, not window (?!)
auto coordsToTransform = cursorPosition.to_win32_point();
ScreenToClient(_hwnd.get(), &coordsToTransform);
cursorPosition = til::point{ coordsToTransform };
ScreenToClient(_hwnd.get(), cursorPosition.as_win32_point());
}
const TerminalInput::MouseButtonState state{
@@ -712,7 +709,7 @@ try
WI_IsFlagSet(GetKeyState(VK_RBUTTON), KeyPressed)
};
return _terminal->SendMouseEvent((cursorPosition / fontSize).to_win32_coord(), uMsg, getControlKeyState(), wheelDelta, state);
return _terminal->SendMouseEvent(cursorPosition / fontSize, uMsg, getControlKeyState(), wheelDelta, state);
}
catch (...)
{
@@ -780,7 +777,7 @@ void _stdcall DestroyTerminal(void* terminal)
}
// Updates the terminal font type, size, color, as well as the background/foreground colors to a specified theme.
void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR fontFamily, short fontSize, int newDpi)
void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR fontFamily, til::CoordType fontSize, int newDpi)
{
const auto publicTerminal = static_cast<HwndTerminal*>(terminal);
{
@@ -810,8 +807,8 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
RECT windowRect;
GetWindowRect(publicTerminal->_hwnd.get(), &windowRect);
COORD dimensions = {};
const SIZE windowSize{ windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
til::size dimensions;
const til::size windowSize{ windowRect.right - windowRect.left, windowRect.bottom - windowRect.top };
publicTerminal->Refresh(windowSize, &dimensions);
}
@@ -984,21 +981,21 @@ void HwndTerminal::_StringPaste(const wchar_t* const pData) noexcept
CATCH_LOG();
}
COORD HwndTerminal::GetFontSize() const noexcept
til::size HwndTerminal::GetFontSize() const noexcept
{
return _actualFont.GetSize();
}
RECT HwndTerminal::GetBounds() const noexcept
til::rect HwndTerminal::GetBounds() const noexcept
{
RECT windowRect;
GetWindowRect(_hwnd.get(), &windowRect);
til::rect windowRect;
GetWindowRect(_hwnd.get(), windowRect.as_win32_rect());
return windowRect;
}
RECT HwndTerminal::GetPadding() const noexcept
til::rect HwndTerminal::GetPadding() const noexcept
{
return { 0 };
return {};
}
double HwndTerminal::GetScaleFactor() const noexcept
@@ -1006,7 +1003,7 @@ double HwndTerminal::GetScaleFactor() const noexcept
return static_cast<double>(_currentDpi) / static_cast<double>(USER_DEFAULT_SCREEN_DPI);
}
void HwndTerminal::ChangeViewport(const SMALL_RECT NewWindow)
void HwndTerminal::ChangeViewport(const til::inclusive_rect& NewWindow)
{
_terminal->UserScrollViewport(NewWindow.Top);
}

View File

@@ -27,16 +27,16 @@ extern "C" {
__declspec(dllexport) HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal);
__declspec(dllexport) void _stdcall TerminalSendOutput(void* terminal, LPCWSTR data);
__declspec(dllexport) void _stdcall TerminalRegisterScrollCallback(void* terminal, void __stdcall callback(int, int, int));
__declspec(dllexport) HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions);
__declspec(dllexport) HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ COORD dimensions, _Out_ SIZE* dimensionsInPixels);
__declspec(dllexport) HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions);
__declspec(dllexport) HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ til::CoordType width, _In_ til::CoordType height, _Out_ til::size* dimensions);
__declspec(dllexport) HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ til::size dimensions, _Out_ til::size* dimensionsInPixels);
__declspec(dllexport) HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ til::CoordType width, _In_ til::CoordType height, _Out_ til::size* dimensions);
__declspec(dllexport) void _stdcall TerminalDpiChanged(void* terminal, int newDpi);
__declspec(dllexport) void _stdcall TerminalUserScroll(void* terminal, int viewTop);
__declspec(dllexport) void _stdcall TerminalClearSelection(void* terminal);
__declspec(dllexport) const wchar_t* _stdcall TerminalGetSelection(void* terminal);
__declspec(dllexport) bool _stdcall TerminalIsSelectionActive(void* terminal);
__declspec(dllexport) void _stdcall DestroyTerminal(void* terminal);
__declspec(dllexport) void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR fontFamily, short fontSize, int newDpi);
__declspec(dllexport) void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR fontFamily, til::CoordType fontSize, int newDpi);
__declspec(dllexport) void _stdcall TerminalRegisterWriteCallback(void* terminal, const void __stdcall callback(wchar_t*));
__declspec(dllexport) void _stdcall TerminalSendKeyEvent(void* terminal, WORD vkey, WORD scanCode, WORD flags, bool keyDown);
__declspec(dllexport) void _stdcall TerminalSendCharEvent(void* terminal, wchar_t ch, WORD flags, WORD scanCode);
@@ -60,7 +60,7 @@ public:
HRESULT Initialize();
void Teardown() noexcept;
void SendOutput(std::wstring_view data);
HRESULT Refresh(const SIZE windowSize, _Out_ COORD* dimensions);
HRESULT Refresh(const til::size windowSize, _Out_ til::size* dimensions);
void RegisterScrollCallback(std::function<void(int, int, int)> callback);
void RegisterWriteCallback(const void _stdcall callback(wchar_t*));
::Microsoft::Console::Types::IUiaData* GetUiaData() const noexcept;
@@ -91,9 +91,9 @@ private:
std::optional<til::point> _singleClickTouchdownPos;
friend HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal);
friend HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions);
friend HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ COORD dimensions, _Out_ SIZE* dimensionsInPixels);
friend HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ short width, _In_ short height, _Out_ COORD* dimensions);
friend HRESULT _stdcall TerminalTriggerResize(_In_ void* terminal, _In_ til::CoordType width, _In_ til::CoordType height, _Out_ til::size* dimensions);
friend HRESULT _stdcall TerminalTriggerResizeWithDimension(_In_ void* terminal, _In_ til::size dimensions, _Out_ til::size* dimensionsInPixels);
friend HRESULT _stdcall TerminalCalculateResize(_In_ void* terminal, _In_ til::CoordType width, _In_ til::CoordType height, _Out_ til::size* dimensions);
friend void _stdcall TerminalDpiChanged(void* terminal, int newDpi);
friend void _stdcall TerminalUserScroll(void* terminal, int viewTop);
friend void _stdcall TerminalClearSelection(void* terminal);
@@ -101,7 +101,7 @@ private:
friend bool _stdcall TerminalIsSelectionActive(void* terminal);
friend void _stdcall TerminalSendKeyEvent(void* terminal, WORD vkey, WORD scanCode, WORD flags, bool keyDown);
friend void _stdcall TerminalSendCharEvent(void* terminal, wchar_t ch, WORD scanCode, WORD flags);
friend void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR fontFamily, short fontSize, int newDpi);
friend void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR fontFamily, til::CoordType fontSize, int newDpi);
friend void _stdcall TerminalBlinkCursor(void* terminal);
friend void _stdcall TerminalSetCursorVisible(void* terminal, const bool visible);
friend void _stdcall TerminalSetFocus(void* terminal);
@@ -128,10 +128,10 @@ private:
void _SendCharEvent(wchar_t ch, WORD scanCode, WORD flags) noexcept;
// Inherited via IControlAccessibilityInfo
COORD GetFontSize() const noexcept override;
RECT GetBounds() const noexcept override;
til::size GetFontSize() const noexcept override;
til::rect GetBounds() const noexcept override;
double GetScaleFactor() const noexcept override;
void ChangeViewport(const SMALL_RECT NewWindow) override;
void ChangeViewport(const til::inclusive_rect& NewWindow) override;
HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) noexcept override;
RECT GetPadding() const noexcept override;
til::rect GetPadding() const noexcept override;
};

View File

@@ -97,7 +97,7 @@ HRESULT OpenTerminalHere::GetTitle(IShellItemArray* /*psiItemArray*/,
return SHStrDup(resource.data(), ppszName);
}
HRESULT OpenTerminalHere::GetState(IShellItemArray* /*psiItemArray*/,
HRESULT OpenTerminalHere::GetState(IShellItemArray* psiItemArray,
BOOL /*fOkToBeSlow*/,
EXPCMDSTATE* pCmdState)
{
@@ -106,10 +106,25 @@ HRESULT OpenTerminalHere::GetState(IShellItemArray* /*psiItemArray*/,
// E_PENDING and this object will be called back on a background thread with
// fOkToBeSlow == TRUE
// We however don't need to bother with any of that, so we'll just return
// ECS_ENABLED.
// We however don't need to bother with any of that.
// If no item was selected when the context menu was opened and Explorer
// is not at a valid path (e.g. This PC or Quick Access), we should hide
// the verb from the context menu.
if (psiItemArray == nullptr)
{
const auto path = this->_GetPathFromExplorer();
*pCmdState = path.empty() ? ECS_HIDDEN : ECS_ENABLED;
}
else
{
winrt::com_ptr<IShellItem> psi;
psiItemArray->GetItemAt(0, psi.put());
SFGAOF attributes;
const bool isFileSystemItem = (psi->GetAttributes(SFGAO_FILESYSTEM, &attributes) == S_OK);
*pCmdState = isFileSystemItem ? ECS_ENABLED : ECS_HIDDEN;
}
*pCmdState = ECS_ENABLED;
return S_OK;
}

View File

@@ -278,6 +278,55 @@ namespace winrt::TerminalApp::implementation
args.Handled(true);
}
void TerminalPage::_HandleScrollToMark(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& realArgs = args.ActionArgs().try_as<ScrollToMarkArgs>())
{
_ApplyToActiveControls([&realArgs](auto& control) {
control.ScrollToMark(realArgs.Direction());
});
}
args.Handled(true);
}
void TerminalPage::_HandleAddMark(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& realArgs = args.ActionArgs().try_as<AddMarkArgs>())
{
_ApplyToActiveControls([realArgs](auto& control) {
Control::ScrollMark mark;
if (realArgs.Color())
{
mark.Color.Color = realArgs.Color().Value();
mark.Color.HasValue = true;
}
else
{
mark.Color.HasValue = false;
}
control.AddMark(mark);
});
}
args.Handled(true);
}
void TerminalPage::_HandleClearMark(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_ApplyToActiveControls([](auto& control) {
control.ClearMark();
});
args.Handled(true);
}
void TerminalPage::_HandleClearAllMarks(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_ApplyToActiveControls([](auto& control) {
control.ClearAllMarks();
});
args.Handled(true);
}
void TerminalPage::_HandleFindMatch(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
@@ -1043,4 +1092,24 @@ namespace winrt::TerminalApp::implementation
args.Handled(true);
}
}
void TerminalPage::_HandleMarkMode(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
{
control.ToggleMarkMode();
args.Handled(true);
}
}
void TerminalPage::_HandleToggleBlockSelection(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
{
const auto handled = control.ToggleBlockSelection();
args.Handled(handled);
}
}
}

View File

@@ -292,7 +292,7 @@ namespace winrt::TerminalApp::implementation
_root->Maximized(true);
}
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode) && !IsQuakeWindow())
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode))
{
_root->SetFullscreen(true);
}

View File

@@ -111,15 +111,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
void DebugTapConnection::_OutputHandler(const hstring str)
{
auto output = til::visualize_control_codes(str);
// To make the output easier to read, we introduce a line break whenever
// an LF control is encountered. But at this point, the LF would have
// been converted to U+240A (␊), so that's what we need to search for.
for (size_t lfPos = 0; (lfPos = output.find(L'\u240A', lfPos)) != std::wstring::npos;)
{
output.insert(++lfPos, L"\r\n");
}
_TerminalOutputHandlers(output);
_TerminalOutputHandlers(til::visualize_control_codes(str));
}
// Called by the DebugInputTapConnection to print user input

View File

@@ -119,7 +119,6 @@
</resheader>
<data name="AppName" xml:space="preserve">
<value>Terminal</value>
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
</data>
<data name="AppNameDev" xml:space="preserve">
<value>Terminal Dev</value>
@@ -127,11 +126,9 @@
</data>
<data name="AppNamePre" xml:space="preserve">
<value>Terminal Preview</value>
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
</data>
<data name="AppStoreName" xml:space="preserve">
<value>Windows Terminal</value>
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
</data>
<data name="AppStoreNameDev" xml:space="preserve">
<value>Windows Terminal Dev</value>
@@ -139,11 +136,9 @@
</data>
<data name="AppStoreNamePre" xml:space="preserve">
<value>Windows Terminal Preview</value>
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
</data>
<data name="AppShortName" xml:space="preserve">
<value>Terminal</value>
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
</data>
<data name="AppShortNameDev" xml:space="preserve">
<value>Terminal Dev</value>
@@ -151,7 +146,6 @@
</data>
<data name="AppShortNamePre" xml:space="preserve">
<value>Terminal Preview</value>
<comment>{Locked=qps-ploc,qps-ploca,qps-plocm}</comment>
</data>
<data name="AppDescription" xml:space="preserve">
<value>The New Windows Terminal</value>

View File

@@ -60,8 +60,7 @@
FontSize="12">
<ToolTipService.ToolTip>
<ToolTip Placement="Mouse">
<TextBlock IsTextSelectionEnabled="False"
TextWrapping="Wrap">
<TextBlock IsTextSelectionEnabled="False">
<Run x:Uid="NewTabRun" /> <LineBreak />
<Run x:Uid="NewPaneRun"
FontStyle="Italic" /> <LineBreak />

View File

@@ -20,7 +20,6 @@
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
<TerminalMUX>true</TerminalMUX>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
@@ -408,6 +407,13 @@
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<!--
By default, the PRI file will contain resource paths beginning with the
project name. Since we enabled XBF embedding, this *also* includes App.xbf.

View File

@@ -1107,8 +1107,8 @@ namespace winrt::TerminalApp::implementation
L".",
L"Azure",
nullptr,
::base::saturated_cast<uint32_t>(settings.InitialRows()),
::base::saturated_cast<uint32_t>(settings.InitialCols()),
settings.InitialRows(),
settings.InitialCols(),
winrt::guid());
if constexpr (Feature_VtPassthroughMode::IsEnabled())
@@ -1158,8 +1158,8 @@ namespace winrt::TerminalApp::implementation
newWorkingDirectory,
settings.StartingTitle(),
envMap.GetView(),
::base::saturated_cast<uint32_t>(settings.InitialRows()),
::base::saturated_cast<uint32_t>(settings.InitialCols()),
settings.InitialRows(),
settings.InitialCols(),
winrt::guid());
valueSet.Insert(L"passthroughMode", Windows::Foundation::PropertyValue::CreateBoolean(settings.VtPassthrough()));
@@ -3274,9 +3274,6 @@ namespace winrt::TerminalApp::implementation
// Request a summon of this window to the foreground
_SummonWindowRequestedHandlers(*this, nullptr);
const IInspectable unused{ nullptr };
_SetAsDefaultDismissHandler(unused, unused);
return S_OK;
}
CATCH_RETURN()

View File

@@ -15,7 +15,6 @@
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
<TerminalMUX>true</TerminalMUX>
</PropertyGroup>
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
@@ -93,6 +92,14 @@
</Reference>
</ItemGroup>
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(OpenConsoleDir)\dep\jsoncpp\json;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>

View File

@@ -9,7 +9,7 @@ using namespace winrt;
using namespace winrt::Windows::Foundation;
using namespace winrt::Microsoft::Terminal::TerminalConnection;
static COORD GetConsoleScreenSize(HANDLE outputHandle)
static til::point GetConsoleScreenSize(HANDLE outputHandle)
{
CONSOLE_SCREEN_BUFFER_INFOEX csbiex{};
csbiex.cbSize = sizeof(csbiex);

View File

@@ -75,8 +75,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
if (settings)
{
_initialRows = winrt::unbox_value_or<uint32_t>(settings.TryLookup(L"initialRows").try_as<Windows::Foundation::IPropertyValue>(), _initialRows);
_initialCols = winrt::unbox_value_or<uint32_t>(settings.TryLookup(L"initialCols").try_as<Windows::Foundation::IPropertyValue>(), _initialCols);
_initialRows = gsl::narrow<til::CoordType>(winrt::unbox_value_or<uint32_t>(settings.TryLookup(L"initialRows").try_as<Windows::Foundation::IPropertyValue>(), _initialRows));
_initialCols = gsl::narrow<til::CoordType>(winrt::unbox_value_or<uint32_t>(settings.TryLookup(L"initialCols").try_as<Windows::Foundation::IPropertyValue>(), _initialCols));
}
}

View File

@@ -32,8 +32,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
WINRT_CALLBACK(TerminalOutput, TerminalOutputHandler);
private:
uint32_t _initialRows{};
uint32_t _initialCols{};
til::CoordType _initialRows{};
til::CoordType _initialCols{};
enum class AzureState
{

View File

@@ -53,12 +53,7 @@ CATCH_RETURN()
HRESULT CTerminalHandoff::s_StopListening()
{
std::unique_lock lock{ _mtx };
return s_StopListeningLocked();
}
// See s_StopListening()
HRESULT CTerminalHandoff::s_StopListeningLocked()
{
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
_pfnHandoff = nullptr;
@@ -106,16 +101,14 @@ HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE sign
{
try
{
std::unique_lock lock{ _mtx };
// s_StopListeningLocked sets _pfnHandoff to nullptr.
// localPfnHandoff is tested for nullness below.
#pragma warning(suppress : 26429) // Symbol '...' is never tested for nullness, it can be marked as not_null (f.23).
// Stash a local copy of _pfnHandoff before we stop listening.
auto localPfnHandoff = _pfnHandoff;
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
// COM does not automatically clean that up for us. We must do it.
LOG_IF_FAILED(s_StopListeningLocked());
s_StopListening();
std::unique_lock lock{ _mtx };
// Report an error if no one registered a handoff function before calling this.
THROW_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);

View File

@@ -43,9 +43,6 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff);
static HRESULT s_StopListening();
private:
static HRESULT s_StopListeningLocked();
};
// Disable warnings from the CoCreatableClass macro as the value it provides for

View File

@@ -293,7 +293,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
_transitionToState(ConnectionState::Connecting);
const COORD dimensions{ gsl::narrow_cast<SHORT>(_initialCols), gsl::narrow_cast<SHORT>(_initialRows) };
const til::size dimensions{ gsl::narrow<til::CoordType>(_initialCols), gsl::narrow<til::CoordType>(_initialRows) };
// If we do not have pipes already, then this is a fresh connection... not an inbound one that is a received
// handoff from an already-started PTY process.
@@ -309,7 +309,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
}
THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(dimensions, flags, &_inPipe, &_outPipe, &_hPC));
THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(til::unwrap_coord_size(dimensions), flags, &_inPipe, &_outPipe, &_hPC));
if (_initialParentHwnd != 0)
{
@@ -338,7 +338,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), dimensions));
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), til::unwrap_coord_size(dimensions)));
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
if (_initialVisibility)

View File

@@ -67,8 +67,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
void _indicateExitWithStatus(unsigned int status) noexcept;
void _ClientTerminated() noexcept;
uint32_t _initialRows{};
uint32_t _initialCols{};
til::CoordType _initialRows{};
til::CoordType _initialCols{};
uint64_t _initialParentHwnd{ 0 };
hstring _commandline{};
hstring _startingDirectory{};

View File

@@ -37,6 +37,28 @@ constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(
namespace winrt::Microsoft::Terminal::Control::implementation
{
static winrt::Microsoft::Terminal::Core::OptionalColor OptionalFromColor(const til::color& c)
{
Core::OptionalColor result;
result.Color = c;
result.HasValue = true;
return result;
}
static winrt::Microsoft::Terminal::Core::OptionalColor OptionalFromColor(const std::optional<til::color>& c)
{
Core::OptionalColor result;
if (c.has_value())
{
result.Color = *c;
result.HasValue = true;
}
else
{
result.HasValue = false;
}
return result;
}
// Helper static function to ensure that all ambiguous-width glyphs are reported as narrow.
// See microsoft/terminal#2066 for more info.
static bool _IsGlyphWideForceNarrowFallback(const std::wstring_view /* glyph */)
@@ -93,9 +115,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnTitleChanged = std::bind(&ControlCore::_terminalTitleChanged, this, std::placeholders::_1);
_terminal->SetTitleChangedCallback(pfnTitleChanged);
auto pfnTabColorChanged = std::bind(&ControlCore::_terminalTabColorChanged, this, std::placeholders::_1);
_terminal->SetTabColorChangedCallback(pfnTabColorChanged);
auto pfnScrollPositionChanged = std::bind(&ControlCore::_terminalScrollPositionChanged, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
_terminal->SetScrollPositionChangedCallback(pfnScrollPositionChanged);
@@ -108,6 +127,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnShowWindowChanged = std::bind(&ControlCore::_terminalShowWindowChanged, this, std::placeholders::_1);
_terminal->SetShowWindowCallback(pfnShowWindowChanged);
auto pfnPlayMidiNote = std::bind(&ControlCore::_terminalPlayMidiNote, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
_terminal->SetPlayMidiNoteCallback(pfnPlayMidiNote);
// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
@@ -126,6 +148,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _terminal.get(), nullptr, 0, std::move(renderThread));
_renderer->SetBackgroundColorChangedCallback([this]() { _rendererBackgroundColorChanged(); });
_renderer->SetFrameColorChangedCallback([this]() { _rendererTabColorChanged(); });
_renderer->SetRendererEnteredErrorStateCallback([weakThis = get_weak()]() {
if (auto strongThis{ weakThis.get() })
@@ -172,12 +195,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
});
// NOTE: Calling UpdatePatternLocations from a background
// thread is a workaround for us to hit GH#12607 less often.
_updatePatternLocations = std::make_unique<til::throttled_func_trailing<>>(
_updatePatternLocations = std::make_shared<ThrottledFuncTrailing<>>(
_dispatcher,
UpdatePatternLocationsInterval,
[weakThis = get_weak()]() {
if (auto core{ weakThis.get() })
if (auto core{ weakThis.get() }; !core->_IsClosing())
{
core->UpdatePatternLocations();
}
@@ -204,6 +226,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_renderer->TriggerTeardown();
}
_shutdownMidiAudio();
}
bool ControlCore::Initialize(const double actualWidth,
@@ -248,8 +272,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// and react accordingly.
_updateFont(true);
const COORD windowSize{ static_cast<short>(windowWidth),
static_cast<short>(windowHeight) };
const til::size windowSize{ static_cast<til::CoordType>(windowWidth),
static_cast<til::CoordType>(windowHeight) };
// First set up the dx engine with the window size in pixels.
// Then, using the font, get the number of characters that can fit.
@@ -393,11 +417,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
vkey != VK_SNAPSHOT &&
keyDown)
{
// try to update the selection
if (const auto updateSlnParams{ ::Terminal::ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) })
if (_terminal->IsInMarkMode() && modifiers.IsCtrlPressed() && vkey == 'A')
{
auto lock = _terminal->LockForWriting();
_terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second);
_terminal->SelectAll();
_renderer->TriggerSelection();
return true;
}
// try to update the selection
if (const auto updateSlnParams{ _terminal->ConvertKeyEventToUpdateSelectionParams(modifiers, vkey) })
{
auto lock = _terminal->LockForWriting();
_terminal->UpdateSelection(updateSlnParams->first, updateSlnParams->second, modifiers);
_renderer->TriggerSelection();
return true;
}
@@ -434,7 +466,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const short wheelDelta,
const TerminalInput::MouseButtonState state)
{
return _terminal->SendMouseEvent(viewportPos.to_win32_coord(), uiButton, states, wheelDelta, state);
return _terminal->SendMouseEvent(viewportPos, uiButton, states, wheelDelta, state);
}
void ControlCore::UserScrollViewport(const int viewTop)
@@ -446,7 +478,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// itself - it was initiated by the mouse wheel, or the scrollbar.
_terminal->UserScrollViewport(viewTop);
(*_updatePatternLocations)();
_updatePatternLocations->Run();
}
void ControlCore::AdjustOpacity(const double adjustment)
@@ -558,12 +590,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_lastHoveredCell = terminalPosition;
uint16_t newId{ 0u };
// we can't use auto here because we're pre-declaring newInterval.
decltype(_terminal->GetHyperlinkIntervalFromPosition(COORD{})) newInterval{ std::nullopt };
decltype(_terminal->GetHyperlinkIntervalFromPosition({})) newInterval{ std::nullopt };
if (terminalPosition.has_value())
{
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
newId = _terminal->GetHyperlinkIdAtPosition(terminalPosition->to_win32_coord());
newInterval = _terminal->GetHyperlinkIntervalFromPosition(terminalPosition->to_win32_coord());
newId = _terminal->GetHyperlinkIdAtPosition(*terminalPosition);
newInterval = _terminal->GetHyperlinkIntervalFromPosition(*terminalPosition);
}
// If the hyperlink ID changed or the interval changed, trigger a redraw all
@@ -593,7 +625,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// Lock for the duration of our reads.
auto lock = _terminal->LockForReading();
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(til::point{ pos }.to_win32_coord()) };
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(til::point{ pos }) };
}
winrt::hstring ControlCore::HoveredUriText() const
@@ -601,7 +633,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto lock = _terminal->LockForReading(); // Lock for the duration of our reads.
if (_lastHoveredCell.has_value())
{
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(_lastHoveredCell->to_win32_coord()) };
return winrt::hstring{ _terminal->GetHyperlinkAtPosition(*_lastHoveredCell) };
}
return {};
}
@@ -648,6 +680,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Inform the renderer of our opacity
_renderEngine->EnableTransparentBackground(_isBackgroundTransparent());
// Trigger a redraw to repaint the window background and tab colors.
_renderer->TriggerRedrawAll(true, true);
_updateAntiAliasingMode();
if (sizeChanged)
@@ -768,7 +803,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool ControlCore::_setFontSizeUnderLock(int fontSize)
{
// Make sure we have a non-zero font size
const auto newSize = std::max<short>(gsl::narrow_cast<short>(fontSize), 1);
const auto newSize = std::max(fontSize, 1);
const auto fontFace = _settings->FontFace();
const auto fontWeight = _settings->FontWeight();
_actualFont = { fontFace, 0, fontWeight.Weight, { 0, newSize }, CP_UTF8, false };
@@ -824,8 +859,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void ControlCore::_refreshSizeUnderLock()
{
auto cx = gsl::narrow_cast<short>(_panelWidth * _compositionScale);
auto cy = gsl::narrow_cast<short>(_panelHeight * _compositionScale);
auto cx = gsl::narrow_cast<til::CoordType>(_panelWidth * _compositionScale);
auto cy = gsl::narrow_cast<til::CoordType>(_panelHeight * _compositionScale);
// Don't actually resize so small that a single character wouldn't fit
// in either dimension. The buffer really doesn't like being size 0.
@@ -893,17 +928,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_refreshSizeUnderLock();
}
void ControlCore::SetSelectionAnchor(const til::point& position)
void ControlCore::SetSelectionAnchor(const til::point position)
{
auto lock = _terminal->LockForWriting();
_terminal->SetSelectionAnchor(position.to_win32_coord());
_terminal->SetSelectionAnchor(position);
}
// Method Description:
// - Sets selection's end position to match supplied cursor position, e.g. while mouse dragging.
// Arguments:
// - position: the point in terminal coordinates (in cells, not pixels)
void ControlCore::SetEndSelectionPoint(const til::point& position)
void ControlCore::SetEndSelectionPoint(const til::point position)
{
if (!_terminal->IsSelectionActive())
{
@@ -920,7 +955,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
};
// save location (for rendering) + render
_terminal->SetSelectionEnd(terminalPosition.to_win32_coord());
_terminal->SetSelectionEnd(terminalPosition);
_renderer->TriggerSelection();
}
@@ -934,14 +969,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Method Description:
// - Given a copy-able selection, get the selected text from the buffer and send it to the
// Windows Clipboard (CascadiaWin32:main.cpp).
// - CopyOnSelect does NOT clear the selection
// Arguments:
// - singleLine: collapse all of the text to one line
// - formats: which formats to copy (defined by action's CopyFormatting arg). nullptr
// if we should defer which formats are copied to the global setting
// - clearSelection: if true, clear the selection. Used for CopyOnSelect.
bool ControlCore::CopySelectionToClipboard(bool singleLine,
const Windows::Foundation::IReference<CopyFormat>& formats,
bool clearSelection)
const Windows::Foundation::IReference<CopyFormat>& formats)
{
// no selection --> nothing to copy
if (!_terminal->IsSelectionActive())
@@ -981,7 +1015,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bgColor) :
"";
if (clearSelection)
if (!_settings->CopyOnSelect())
{
_terminal->ClearSelection();
_renderer->TriggerSelection();
@@ -1003,9 +1037,28 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderer->TriggerSelection();
}
const bool ControlCore::IsInQuickEditMode() const noexcept
bool ControlCore::ToggleBlockSelection()
{
return _terminal->IsInQuickEditMode();
auto lock = _terminal->LockForWriting();
if (_terminal->IsSelectionActive())
{
_terminal->SetBlockSelection(!_terminal->IsBlockSelection());
_renderer->TriggerSelection();
return true;
}
return false;
}
void ControlCore::ToggleMarkMode()
{
auto lock = _terminal->LockForWriting();
_terminal->ToggleMarkMode();
_renderer->TriggerSelection();
}
bool ControlCore::IsInMarkMode() const
{
return _terminal->IsInMarkMode();
}
// Method Description:
@@ -1151,21 +1204,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_TitleChangedHandlers(*this, winrt::make<TitleChangedEventArgs>(winrt::hstring{ wstr }));
}
// Method Description:
// - Called for the Terminal's TabColorChanged callback. This will re-raise
// a new winrt TypedEvent that can be listened to.
// - The listeners to this event will re-query the control for the current
// value of TabColor().
// Arguments:
// - <unused>
// Return Value:
// - <none>
void ControlCore::_terminalTabColorChanged(const std::optional<til::color> /*color*/)
{
// Raise a TabColorChanged event
_TabColorChangedHandlers(*this, nullptr);
}
// Method Description:
// - Update the position and size of the scrollbar to match the given
// viewport top, viewport height, and buffer size.
@@ -1180,6 +1218,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const int viewHeight,
const int bufferSize)
{
if (!_initializedTerminal)
{
return;
}
// Clear the regex pattern tree so the renderer does not try to render them while scrolling
// We're **NOT** taking the lock here unlike _scrollbarChangeHandler because
// we are already under lock (since this usually happens as a result of writing).
@@ -1200,7 +1242,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// Additionally, start the throttled update of where our links are.
(*_updatePatternLocations)();
_updatePatternLocations->Run();
}
void ControlCore::_terminalCursorPositionChanged()
@@ -1224,6 +1266,66 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
// Method Description:
// - Plays a single MIDI note, blocking for the duration.
// Arguments:
// - noteNumber - The MIDI note number to be played (0 - 127).
// - velocity - The force with which the note should be played (0 - 127).
// - duration - How long the note should be sustained (in microseconds).
void ControlCore::_terminalPlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration)
{
// We create the audio instance on demand, and lock it for the duration
// of the note output so it can't be destroyed while in use.
auto& midiAudio = _getMidiAudio();
midiAudio.Lock();
// We then unlock the terminal, so the UI doesn't hang while we're busy.
auto& terminalLock = _terminal->GetReadWriteLock();
terminalLock.unlock();
// This call will block for the duration, unless shutdown early.
midiAudio.PlayNote(noteNumber, velocity, duration);
// Once complete, we reacquire the terminal lock and unlock the audio.
// If the terminal has shutdown in the meantime, the Unlock call
// will throw an exception, forcing the thread to exit ASAP.
terminalLock.lock();
midiAudio.Unlock();
}
// Method Description:
// - Returns the MIDI audio instance, created on demand.
// Arguments:
// - <none>
// Return Value:
// - a reference to the MidiAudio instance.
MidiAudio& ControlCore::_getMidiAudio()
{
if (!_midiAudio)
{
_midiAudio = std::make_unique<MidiAudio>();
_midiAudio->Initialize();
}
return *_midiAudio;
}
// Method Description:
// - Shuts down the MIDI audio system if previously instantiated.
// Arguments:
// - <none>
// Return Value:
// - <none>
void ControlCore::_shutdownMidiAudio()
{
if (_midiAudio)
{
// We lock the terminal here to make sure the shutdown promise is
// set before the audio is unlocked in the thread that is playing.
auto lock = _terminal->LockForWriting();
_midiAudio->Shutdown();
}
}
bool ControlCore::HasSelection() const
{
return _terminal->IsSelectionActive();
@@ -1366,6 +1468,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_BackgroundColorChangedHandlers(*this, nullptr);
}
void ControlCore::_rendererTabColorChanged()
{
_TabColorChangedHandlers(*this, nullptr);
}
void ControlCore::BlinkAttributeTick()
{
auto lock = _terminal->LockForWriting();
@@ -1419,7 +1526,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
auto lock = _terminal->LockForReading();
return _terminal->GetViewportRelativeCursorPosition().to_core_point();
return _terminal->GetCursorPosition().to_core_point();
}
// This one's really pushing the boundary of what counts as "encapsulation".
@@ -1471,7 +1578,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// If shift is pressed and there is a selection we extend it using
// the selection mode (expand the "end" selection point)
_terminal->SetSelectionEnd(terminalPosition.to_win32_coord(), mode);
_terminal->SetSelectionEnd(terminalPosition, mode);
selectionNeedsToBeCopied = true;
}
else if (mode != ::Terminal::SelectionExpansion::Char || shiftEnabled)
@@ -1479,7 +1586,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// If we are handling a double / triple-click or shift+single click
// we establish selection using the selected mode
// (expand both "start" and "end" selection points)
_terminal->MultiClickSelection(terminalPosition.to_win32_coord(), mode);
_terminal->MultiClickSelection(terminalPosition, mode);
selectionNeedsToBeCopied = true;
}
@@ -1509,10 +1616,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
void ControlCore::_connectionOutputHandler(const hstring& hstr)
{
_terminal->Write(hstr);
try
{
_terminal->Write(hstr);
// Start the throttled update of where our hyperlinks are.
(*_updatePatternLocations)();
// Start the throttled update of where our hyperlinks are.
_updatePatternLocations->Run();
}
catch (...)
{
// We're expecting to receive an exception here if the terminal
// is closed while we're blocked playing a MIDI note.
}
}
// Method Description:
@@ -1744,24 +1859,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - This is related to work done for GH#2988.
void ControlCore::GotFocus()
{
_focusChanged(true);
_terminal->FocusChanged(true);
}
// See GotFocus.
void ControlCore::LostFocus()
{
_focusChanged(false);
}
void ControlCore::_focusChanged(bool focused)
{
// GH#13461 - temporarily turn off read-only mode, send the focus event,
// then turn it back on. Even in focus mode, focus events are fine to
// send. We don't want to pop a warning every time the control is
// focused.
const auto previous = std::exchange(_isReadOnly, false);
const auto restore = wil::scope_exit([&]() { _isReadOnly = previous; });
_terminal->FocusChanged(focused);
_terminal->FocusChanged(false);
}
bool ControlCore::_isBackgroundTransparent()
@@ -1793,4 +1897,140 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
_owningHwnd = owner;
}
Windows::Foundation::Collections::IVector<Control::ScrollMark> ControlCore::ScrollMarks() const
{
auto internalMarks{ _terminal->GetScrollMarks() };
auto v = winrt::single_threaded_observable_vector<Control::ScrollMark>();
for (const auto& mark : internalMarks)
{
Control::ScrollMark m{};
// sneaky: always evaluate the color of the mark to a real value
// before shoving it into the optional. If the mark doesn't have a
// specific color set, we'll use the value from the color table
// that's appropriate for this category of mark. If we do have a
// color set, then great we'll use that. The TermControl can then
// always use the value in the Mark regardless if it was actually
// set or not.
m.Color = OptionalFromColor(_terminal->GetColorForMark(mark));
m.Start = mark.start.to_core_point();
m.End = mark.end.to_core_point();
v.Append(m);
}
return v;
}
void ControlCore::AddMark(const Control::ScrollMark& mark)
{
::Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark m{};
if (mark.Color.HasValue)
{
m.color = til::color{ mark.Color.Color };
}
if (HasSelection())
{
m.start = til::point{ _terminal->GetSelectionAnchor() };
m.end = til::point{ _terminal->GetSelectionEnd() };
}
else
{
m.start = m.end = til::point{ _terminal->GetTextBuffer().GetCursor().GetPosition() };
}
// The version of this that only accepts a ScrollMark will automatically
// set the start & end to the cursor position.
_terminal->AddMark(m, m.start, m.end);
}
void ControlCore::ClearMark() { _terminal->ClearMark(); }
void ControlCore::ClearAllMarks() { _terminal->ClearAllMarks(); }
void ControlCore::ScrollToMark(const Control::ScrollToMarkDirection& direction)
{
const auto currentOffset = ScrollOffset();
const auto& marks{ _terminal->GetScrollMarks() };
std::optional<DispatchTypes::ScrollMark> tgt;
switch (direction)
{
case ScrollToMarkDirection::Last:
{
int highest = currentOffset;
for (const auto& mark : marks)
{
const auto newY = mark.start.y;
if (newY > highest)
{
tgt = mark;
highest = newY;
}
}
break;
}
case ScrollToMarkDirection::First:
{
int lowest = currentOffset;
for (const auto& mark : marks)
{
const auto newY = mark.start.y;
if (newY < lowest)
{
tgt = mark;
lowest = newY;
}
}
break;
}
case ScrollToMarkDirection::Next:
{
int minDistance = INT_MAX;
for (const auto& mark : marks)
{
const auto delta = mark.start.y - currentOffset;
if (delta > 0 && delta < minDistance)
{
tgt = mark;
minDistance = delta;
}
}
break;
}
case ScrollToMarkDirection::Previous:
default:
{
int minDistance = INT_MAX;
for (const auto& mark : marks)
{
const auto delta = currentOffset - mark.start.y;
if (delta > 0 && delta < minDistance)
{
tgt = mark;
minDistance = delta;
}
}
break;
}
}
if (tgt.has_value())
{
UserScrollViewport(tgt->start.y);
}
else
{
if (direction == ScrollToMarkDirection::Last || direction == ScrollToMarkDirection::Next)
{
UserScrollViewport(BufferHeight());
}
else if (direction == ScrollToMarkDirection::First || direction == ScrollToMarkDirection::Previous)
{
UserScrollViewport(0);
}
}
}
}

View File

@@ -17,6 +17,7 @@
#include "ControlCore.g.h"
#include "ControlSettings.h"
#include "../../audio/midi/MidiAudio.hpp"
#include "../../renderer/base/Renderer.hpp"
#include "../../cascadia/TerminalCore/Terminal.hpp"
#include "../buffer/out/search.h"
@@ -79,9 +80,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SendInput(const winrt::hstring& wstr);
void PasteText(const winrt::hstring& hstr);
bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats, bool clearSelection = true);
bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats);
void SelectAll();
const bool IsInQuickEditMode() const noexcept;
bool ToggleBlockSelection();
void ToggleMarkMode();
bool IsInMarkMode() const;
void GotFocus();
void LostFocus();
@@ -116,6 +119,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
int BufferHeight() const;
bool BracketedPasteEnabled() const noexcept;
Windows::Foundation::Collections::IVector<Control::ScrollMark> ScrollMarks() const;
void AddMark(const Control::ScrollMark& mark);
void ClearMark();
void ClearAllMarks();
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
#pragma endregion
#pragma region ITerminalInput
@@ -149,8 +159,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool HasSelection() const;
bool CopyOnSelect() const;
Windows::Foundation::Collections::IVector<winrt::hstring> SelectedText(bool trimTrailingWhitespace) const;
void SetSelectionAnchor(const til::point& position);
void SetEndSelectionPoint(const til::point& position);
void SetSelectionAnchor(const til::point position);
void SetEndSelectionPoint(const til::point position);
void Search(const winrt::hstring& text,
const bool goForward,
@@ -251,7 +261,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
std::unique_ptr<til::throttled_func_trailing<>> _updatePatternLocations;
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
winrt::fire_and_forget _asyncCloseConnection();
@@ -266,19 +276,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _terminalCopyToClipboard(std::wstring_view wstr);
void _terminalWarningBell();
void _terminalTitleChanged(std::wstring_view wstr);
void _terminalTabColorChanged(const std::optional<til::color> color);
void _terminalScrollPositionChanged(const int viewTop,
const int viewHeight,
const int bufferSize);
void _terminalCursorPositionChanged();
void _terminalTaskbarProgressChanged();
void _terminalShowWindowChanged(bool showOrHide);
void _terminalPlayMidiNote(const int noteNumber,
const int velocity,
const std::chrono::microseconds duration);
#pragma endregion
std::unique_ptr<MidiAudio> _midiAudio;
MidiAudio& _getMidiAudio();
void _shutdownMidiAudio();
#pragma region RendererCallbacks
void _rendererWarning(const HRESULT hr);
void _renderEngineSwapChainChanged();
void _rendererBackgroundColorChanged();
void _rendererTabColorChanged();
#pragma endregion
void _raiseReadOnlyWarning();
@@ -288,7 +306,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _setOpacity(const double opacity);
bool _isBackgroundTransparent();
void _focusChanged(bool focused);
inline bool _IsClosing() const noexcept
{

View File

@@ -22,7 +22,6 @@ namespace Microsoft.Terminal.Control
IsRightButtonDown = 0x4
};
enum ClearBufferType
{
Screen,
@@ -66,7 +65,10 @@ namespace Microsoft.Terminal.Control
void SendInput(String text);
void PasteText(String text);
void SelectAll();
Boolean ToggleBlockSelection();
void ToggleMarkMode();
void ClearBuffer(ClearBufferType clearType);
Boolean IsInMarkMode();
void SetHoveredCell(Microsoft.Terminal.Core.Point terminalPosition);
void ClearHoveredCell();

View File

@@ -142,14 +142,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Method Description:
// - Given a copy-able selection, get the selected text from the buffer and send it to the
// Windows Clipboard (CascadiaWin32:main.cpp).
// - CopyOnSelect does NOT clear the selection
// Arguments:
// - singleLine: collapse all of the text to one line
// - formats: which formats to copy (defined by action's CopyFormatting arg). nullptr
// if we should defer which formats are copied to the global setting
// - clearSelection: if true, clear the selection after copying it. Used for CopyOnSelect.
bool ControlInteractivity::CopySelectionToClipboard(bool singleLine,
const Windows::Foundation::IReference<CopyFormat>& formats,
bool clearSelection)
const Windows::Foundation::IReference<CopyFormat>& formats)
{
if (_core)
{
@@ -165,7 +164,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Mark the current selection as copied
_selectionNeedsToBeCopied = false;
return _core->CopySelectionToClipboard(singleLine, formats, clearSelection);
return _core->CopySelectionToClipboard(singleLine, formats);
}
return false;
@@ -258,26 +257,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
else if (WI_IsFlagSet(buttonState, MouseButtonState::IsRightButtonDown))
{
if (_core->CopyOnSelect())
// CopyOnSelect right click always pastes
if (_core->CopyOnSelect() || !_core->HasSelection())
{
// CopyOnSelect:
// 1. keyboard selection? --> copy the new content first
// 2. right click always pastes!
if (_core->IsInQuickEditMode())
{
CopySelectionToClipboard(shiftEnabled, nullptr);
}
RequestPasteTextFromClipboard();
}
else if (_core->HasSelection())
{
// copy selected text
CopySelectionToClipboard(shiftEnabled, nullptr);
}
else
{
// no selection --> paste
RequestPasteTextFromClipboard();
CopySelectionToClipboard(shiftEnabled, nullptr);
}
}
}
@@ -396,10 +383,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
isLeftMouseRelease &&
_selectionNeedsToBeCopied)
{
// IMPORTANT!
// Set clearSelection to false here!
// Otherwise, the selection will be cleared immediately after you make it.
CopySelectionToClipboard(false, nullptr, /*clearSelection*/ false);
CopySelectionToClipboard(false, nullptr);
}
_singleClickTouchdownPos = std::nullopt;
@@ -631,7 +615,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Get the size of the font, which is in pixels
const til::size fontSize{ _core->GetFont().GetSize() };
// Convert the location in pixels to characters within the current viewport.
return til::point{ pixelPosition / fontSize };
return pixelPosition / fontSize;
}
bool ControlInteractivity::_sendMouseEventHelper(const til::point terminalPosition,

View File

@@ -80,8 +80,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma endregion
bool CopySelectionToClipboard(bool singleLine,
const Windows::Foundation::IReference<CopyFormat>& formats,
bool clearSelection = true);
const Windows::Foundation::IReference<CopyFormat>& formats);
void RequestPasteTextFromClipboard();
void SetEndSelectionPoint(const Core::Point pixelPosition);
bool ManglePathsForWsl();
@@ -124,7 +123,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// terminal.
bool _selectionNeedsToBeCopied;
std::optional<COORD> _lastHoveredCell{ std::nullopt };
std::optional<til::point> _lastHoveredCell{ std::nullopt };
// Track the last hyperlink ID we hovered over
uint16_t _lastHoveredId{ 0 };

View File

@@ -56,6 +56,7 @@ namespace Microsoft.Terminal.Control
// Experimental Settings
Boolean ForceFullRepaintRendering { get; };
Boolean SoftwareRendering { get; };
Boolean ShowMarks { get; };
Boolean UseBackgroundImageForWindow { get; };
};
}

View File

@@ -3,6 +3,32 @@
namespace Microsoft.Terminal.Control
{
enum MarkCategory
{
Prompt = 0,
Error = 1,
Warning = 2,
Info = 3
};
struct ScrollMark
{
// There are other members of DispatchTypes::ScrollMark, but these are
// all we need to expose up and set downwards currently. Additional
// members can be bubbled as necessary.
Microsoft.Terminal.Core.Point Start;
Microsoft.Terminal.Core.Point End; // exclusive
Microsoft.Terminal.Core.OptionalColor Color;
};
enum ScrollToMarkDirection
{
Previous,
Next,
First,
Last
};
// These are properties of the TerminalCore that should be queryable by the
// rest of the app.
interface ICoreState
@@ -27,5 +53,11 @@ namespace Microsoft.Terminal.Control
UInt64 OwningHwnd;
void AddMark(ScrollMark mark);
void ClearMark();
void ClearAllMarks();
void ScrollToMark(ScrollToMarkDirection direction);
IVector<ScrollMark> ScrollMarks { get; };
};
}

View File

@@ -146,14 +146,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma endregion
#pragma region IControlAccessibilityInfo
COORD InteractivityAutomationPeer::GetFontSize() const noexcept
til::size InteractivityAutomationPeer::GetFontSize() const noexcept
{
return til::size{ til::math::rounding, _interactivity->Core().FontSize() }.to_win32_coord();
return { til::math::rounding, _interactivity->Core().FontSize() };
}
RECT InteractivityAutomationPeer::GetBounds() const noexcept
til::rect InteractivityAutomationPeer::GetBounds() const noexcept
{
return _controlBounds.to_win32_rect();
return _controlBounds;
}
HRESULT InteractivityAutomationPeer::GetHostUiaProvider(IRawElementProviderSimple** provider)
@@ -164,9 +164,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return S_OK;
}
RECT InteractivityAutomationPeer::GetPadding() const noexcept
til::rect InteractivityAutomationPeer::GetPadding() const noexcept
{
return _controlPadding.to_win32_rect();
return _controlPadding;
}
double InteractivityAutomationPeer::GetScaleFactor() const noexcept
@@ -174,7 +174,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
}
void InteractivityAutomationPeer::ChangeViewport(const SMALL_RECT NewWindow)
void InteractivityAutomationPeer::ChangeViewport(const til::inclusive_rect& NewWindow)
{
_interactivity->UpdateScrollbar(NewWindow.Top);
}

View File

@@ -63,11 +63,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma region IControlAccessibilityInfo Pattern
// Inherited via IControlAccessibilityInfo
virtual COORD GetFontSize() const noexcept override;
virtual RECT GetBounds() const noexcept override;
virtual RECT GetPadding() const noexcept override;
virtual til::size GetFontSize() const noexcept override;
virtual til::rect GetBounds() const noexcept override;
virtual til::rect GetPadding() const noexcept override;
virtual double GetScaleFactor() const noexcept override;
virtual void ChangeViewport(SMALL_RECT NewWindow) override;
virtual void ChangeViewport(const til::inclusive_rect& NewWindow) override;
virtual HRESULT GetHostUiaProvider(IRawElementProviderSimple** provider) override;
#pragma endregion

View File

@@ -124,20 +124,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
[weakThis = get_weak()](const auto& update) {
if (auto control{ weakThis.get() }; !control->_IsClosing())
{
control->_isInternalScrollBarUpdate = true;
auto scrollBar = control->ScrollBar();
if (update.newValue)
{
scrollBar.Value(*update.newValue);
}
scrollBar.Maximum(update.newMaximum);
scrollBar.Minimum(update.newMinimum);
scrollBar.ViewportSize(update.newViewportSize);
// scroll one full screen worth at a time when the scroll bar is clicked
scrollBar.LargeChange(std::max(update.newViewportSize - 1, 0.));
control->_isInternalScrollBarUpdate = false;
control->_throttledUpdateScrollbar(update);
}
});
@@ -148,6 +135,57 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_ApplyUISettings();
}
void TermControl::_throttledUpdateScrollbar(const ScrollBarUpdate& update)
{
// Assumptions:
// * we're already not closing
// * caller already checked weak ptr to make sure we're still alive
_isInternalScrollBarUpdate = true;
auto scrollBar = ScrollBar();
if (update.newValue)
{
scrollBar.Value(*update.newValue);
}
scrollBar.Maximum(update.newMaximum);
scrollBar.Minimum(update.newMinimum);
scrollBar.ViewportSize(update.newViewportSize);
// scroll one full screen worth at a time when the scroll bar is clicked
scrollBar.LargeChange(std::max(update.newViewportSize - 1, 0.));
_isInternalScrollBarUpdate = false;
if (_showMarksInScrollbar)
{
// Update scrollbar marks
ScrollBarCanvas().Children().Clear();
const auto marks{ _core.ScrollMarks() };
const auto fullHeight{ ScrollBarCanvas().ActualHeight() };
const auto totalBufferRows{ update.newMaximum + update.newViewportSize };
for (const auto m : marks)
{
Windows::UI::Xaml::Shapes::Rectangle r;
Media::SolidColorBrush brush{};
// Sneaky: technically, a mark doesn't need to have a color set,
// it might want to just use the color from the palette for that
// kind of mark. Fortunately, ControlCore is kind enough to
// pre-evaluate that for us, and shove the real value into the
// Color member, regardless if the mark has a literal value set.
brush.Color(static_cast<til::color>(m.Color.Color));
r.Fill(brush);
r.Width(16.0f / 3.0f); // pip width - 1/3rd of the scrollbar width.
r.Height(2);
const auto markRow = m.Start.Y;
const auto fractionalHeight = markRow / totalBufferRows;
const auto relativePos = fractionalHeight * fullHeight;
ScrollBarCanvas().Children().Append(r);
Windows::UI::Xaml::Controls::Canvas::SetTop(r, relativePos);
}
}
}
// Method Description:
// - Loads the search box from the xaml UI and focuses it.
void TermControl::CreateSearchBoxControl()
@@ -404,6 +442,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
newMargin.Right,
newMargin.Bottom });
}
_showMarksInScrollbar = settings.ShowMarks();
// Clear out all the current marks
ScrollBarCanvas().Children().Clear();
// When we hot reload the settings, the core will send us a scrollbar
// update. If we enabled scrollbar marks, then great, when we handle
// that message, we'll redraw them.
}
// Method Description:
@@ -637,7 +682,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// clever way around asking the core for this.
til::point TermControl::GetFontSize() const
{
return til::point{ til::math::rounding, _core.FontSize().Width, _core.FontSize().Height };
return { til::math::rounding, _core.FontSize().Width, _core.FontSize().Height };
}
const Windows::UI::Xaml::Thickness TermControl::GetPadding()
@@ -1137,7 +1182,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// Manually show the cursor when a key is pressed. Restarting
// the timer prevents flickering.
_core.CursorOn(true);
_core.CursorOn(!_core.IsInMarkMode());
_cursorTimer->Start();
}
@@ -1608,7 +1653,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_cursorTimer)
{
// When the terminal focuses, show the cursor immediately
_core.CursorOn(true);
_core.CursorOn(!_core.IsInMarkMode());
_cursorTimer->Start();
}
@@ -1859,6 +1904,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_core.SelectAll();
}
bool TermControl::ToggleBlockSelection()
{
return _core.ToggleBlockSelection();
}
void TermControl::ToggleMarkMode()
{
_core.ToggleMarkMode();
}
void TermControl::Close()
{
if (!_IsClosing())
@@ -1964,7 +2019,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// The family is only used to determine if the font is truetype or
// not, but DX doesn't use that info at all.
// The Codepage is additionally not actually used by the DX engine at all.
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, gsl::narrow_cast<short>(fontSize) }, CP_UTF8, false };
FontInfo actualFont = { fontFace, 0, fontWeight.Weight, { 0, fontSize }, CP_UTF8, false };
FontInfoDesired desiredFont = { actualFont };
// Create a DX engine and initialize it with our font and DPI. We'll
@@ -2853,4 +2908,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core.OwningHwnd();
}
void TermControl::AddMark(const Control::ScrollMark& mark)
{
_core.AddMark(mark);
}
void TermControl::ClearMark() { _core.ClearMark(); }
void TermControl::ClearAllMarks() { _core.ClearAllMarks(); }
void TermControl::ScrollToMark(const Control::ScrollToMarkDirection& direction) { _core.ScrollToMark(direction); }
Windows::Foundation::Collections::IVector<Control::ScrollMark> TermControl::ScrollMarks() const
{
return _core.ScrollMarks();
}
}

View File

@@ -38,6 +38,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference<CopyFormat>& formats);
void PasteTextFromClipboard();
void SelectAll();
bool ToggleBlockSelection();
void ToggleMarkMode();
void Close();
Windows::Foundation::Size CharacterDimensions() const;
Windows::Foundation::Size MinimumSize();
@@ -65,6 +67,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
uint64_t OwningHwnd();
void OwningHwnd(uint64_t owner);
Windows::Foundation::Collections::IVector<Control::ScrollMark> ScrollMarks() const;
void AddMark(const Control::ScrollMark& mark);
void ClearMark();
void ClearAllMarks();
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
#pragma endregion
void ScrollViewport(int viewTop);
@@ -193,6 +202,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::optional<Windows::UI::Xaml::DispatcherTimer> _blinkTimer;
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
bool _showMarksInScrollbar{ false };
inline bool _IsClosing() const noexcept
{
@@ -285,6 +295,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
void _coreFoundMatch(const IInspectable& sender, const Control::FoundResultsArgs& args);
void _throttledUpdateScrollbar(const ScrollBarUpdate& update);
};
}

View File

@@ -51,6 +51,8 @@ namespace Microsoft.Terminal.Control
Boolean CopySelectionToClipboard(Boolean singleLine, Windows.Foundation.IReference<CopyFormat> formats);
void PasteTextFromClipboard();
void SelectAll();
Boolean ToggleBlockSelection();
void ToggleMarkMode();
void ClearBuffer(ClearBufferType clearType);
void Close();
Windows.Foundation.Size CharacterDimensions { get; };

View File

@@ -1243,6 +1243,30 @@
Style="{StaticResource ForkedScrollbarTemplate}"
ValueChanged="_ScrollbarChangeHandler"
ViewportSize="10" />
<Grid x:Name="ScrollMarksGrid"
Grid.Column="1"
Width="{StaticResource ScrollBarSize}"
HorizontalAlignment="Right"
VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.Row="0"
Height="{StaticResource ScrollBarSize}" />
<Canvas x:Name="ScrollBarCanvas"
Grid.Row="1"
Width="{StaticResource ScrollBarSize}"
HorizontalAlignment="Right"
VerticalAlignment="Stretch" />
<Border Grid.Row="2"
Height="{StaticResource ScrollBarSize}" />
</Grid>
</Grid>
<local:TSFInputControl x:Name="TSFInputControl"

View File

@@ -147,9 +147,14 @@
<PRIResource Include="Resources\en-US\Resources.resw" />
<OCResourceDirectory Include="Resources" />
</ItemGroup>
<ItemGroup Condition="'$(WindowsTerminalBranding)'=='' or '$(WindowsTerminalBranding)'=='Dev' or '$(WindowsTerminalBranding)'=='Preview'">
<!-- GH#13252 Only vend this dependency for Dev and Preview builds. -->
<SDKReference Include="Microsoft.Midi.GmDls, Version=10.0.22000.0" />
</ItemGroup>
<!-- ========================= Project References ======================== -->
<ItemGroup>
<ProjectReference Include="..\..\types\lib\types.vcxproj" />
<ProjectReference Include="..\..\audio\midi\lib\midi.vcxproj" />
<ProjectReference Include="..\..\buffer\out\lib\bufferout.vcxproj" />
<ProjectReference Include="$(OpenConsoleDir)src\renderer\base\lib\base.vcxproj" />
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj" />

View File

@@ -45,6 +45,7 @@
#include <winrt/Windows.UI.Xaml.Input.h>
#include <winrt/Windows.UI.Xaml.Interop.h>
#include <winrt/Windows.ui.xaml.markup.h>
#include <winrt/Windows.ui.xaml.shapes.h>
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
#include <winrt/Windows.Storage.h>

View File

@@ -24,6 +24,15 @@ namespace Microsoft.Terminal.Core
UInt8 A;
};
// Yes, this is also just an IReference<Color>. However, IReference has some
// weird ownership semantics that just make it a pain for something as
// simple as "maybe this color doesn't have a value set".
struct OptionalColor
{
Boolean HasValue;
Microsoft.Terminal.Core.Color Color;
};
// TerminalCore declares its own Color struct to avoid depending on
// Windows.UI. Windows.Foundation.Point also exists, but it's composed of
// floating-point coordinates, when we almost always need integer coordinates.

View File

@@ -26,6 +26,9 @@ namespace Microsoft.Terminal.Core
Windows.Foundation.IReference<Microsoft.Terminal.Core.Color> TabColor;
Windows.Foundation.IReference<Microsoft.Terminal.Core.Color> StartingTabColor;
Boolean AutoMarkPrompts;
};
}

View File

@@ -17,10 +17,10 @@ namespace Microsoft::Terminal::Core
ITerminalInput& operator=(ITerminalInput&&) = default;
virtual bool SendKeyEvent(const WORD vkey, const WORD scanCode, const ControlKeyStates states, const bool keyDown) = 0;
virtual bool SendMouseEvent(const COORD viewportPos, const unsigned int uiButton, const ControlKeyStates states, const short wheelDelta, const Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState state) = 0;
virtual bool SendMouseEvent(const til::point viewportPos, const unsigned int uiButton, const ControlKeyStates states, const short wheelDelta, const Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState state) = 0;
virtual bool SendCharEvent(const wchar_t ch, const WORD scanCode, const ControlKeyStates states) = 0;
[[nodiscard]] virtual HRESULT UserResize(const COORD size) noexcept = 0;
[[nodiscard]] virtual HRESULT UserResize(const til::size size) noexcept = 0;
virtual void UserScrollViewport(const int viewTop) = 0;
virtual int GetScrollOffset() = 0;

View File

@@ -45,11 +45,12 @@ Terminal::Terminal() :
_snapOnInput{ true },
_altGrAliasing{ true },
_blockSelection{ false },
_quickEditMode{ false },
_markMode{ false },
_selection{ std::nullopt },
_taskbarState{ 0 },
_taskbarProgress{ 0 },
_trimBlockSelection{ false }
_trimBlockSelection{ false },
_autoMarkPrompts{ false }
{
auto passAlongInput = [&](std::deque<std::unique_ptr<IInputEvent>>& inEventsToWrite) {
if (!_pfnWriteInput)
@@ -66,12 +67,12 @@ Terminal::Terminal() :
_renderSettings.SetColorAlias(ColorAlias::DefaultBackground, TextColor::DEFAULT_BACKGROUND, RGB(0, 0, 0));
}
void Terminal::Create(COORD viewportSize, SHORT scrollbackLines, Renderer& renderer)
void Terminal::Create(til::size viewportSize, til::CoordType scrollbackLines, Renderer& renderer)
{
_mutableViewport = Viewport::FromDimensions({ 0, 0 }, viewportSize);
_scrollbackLines = scrollbackLines;
const COORD bufferSize{ viewportSize.X,
Utils::ClampToShortMax(viewportSize.Y + scrollbackLines, 1) };
const til::size bufferSize{ viewportSize.X,
Utils::ClampToShortMax(viewportSize.Y + scrollbackLines, 1) };
const TextAttribute attr{};
const UINT cursorSize = 12;
_mainBuffer = std::make_unique<TextBuffer>(bufferSize, attr, cursorSize, true, renderer);
@@ -97,8 +98,8 @@ void Terminal::Create(COORD viewportSize, SHORT scrollbackLines, Renderer& rende
void Terminal::CreateFromSettings(ICoreSettings settings,
Renderer& renderer)
{
const COORD viewportSize{ Utils::ClampToShortMax(settings.InitialCols(), 1),
Utils::ClampToShortMax(settings.InitialRows(), 1) };
const til::size viewportSize{ Utils::ClampToShortMax(settings.InitialCols(), 1),
Utils::ClampToShortMax(settings.InitialRows(), 1) };
// TODO:MSFT:20642297 - Support infinite scrollback here, if HistorySize is -1
Create(viewportSize, Utils::ClampToShortMax(settings.HistorySize(), 0), renderer);
@@ -121,16 +122,17 @@ void Terminal::UpdateSettings(ICoreSettings settings)
_suppressApplicationTitle = settings.SuppressApplicationTitle();
_startingTitle = settings.StartingTitle();
_trimBlockSelection = settings.TrimBlockSelection();
_autoMarkPrompts = settings.AutoMarkPrompts();
_terminalInput->ForceDisableWin32InputMode(settings.ForceVTInput());
if (settings.TabColor() == nullptr)
{
_tabColor = std::nullopt;
_renderSettings.SetColorTableEntry(TextColor::FRAME_BACKGROUND, INVALID_COLOR);
}
else
{
_tabColor = settings.TabColor().Value();
_renderSettings.SetColorTableEntry(TextColor::FRAME_BACKGROUND, til::color{ settings.TabColor().Value() });
}
if (!_startingTabColor && settings.StartingTabColor())
@@ -138,11 +140,6 @@ void Terminal::UpdateSettings(ICoreSettings settings)
_startingTabColor = settings.StartingTabColor().Value();
}
if (_pfnTabColorChanged)
{
_pfnTabColorChanged(GetTabColor());
}
// TODO:MSFT:21327402 - if HistorySize has changed, resize the buffer so we
// have a smaller scrollback. We should do this carefully - if the new buffer
// size is smaller than where the mutable viewport currently is, we'll want
@@ -216,6 +213,11 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
}
_defaultCursorShape = cursorShape;
// Tell the control that the scrollbar has somehow changed. Used as a
// workaround to force the control to redraw any scrollbar marks whose color
// may have changed.
_NotifyScrollEvent();
}
void Terminal::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle)
@@ -248,7 +250,7 @@ std::wstring_view Terminal::GetWorkingDirectory()
// - S_OK if we successfully resized the terminal, S_FALSE if there was
// nothing to do (the viewportSize is the same as our current size), or an
// appropriate HRESULT for failing to resize.
[[nodiscard]] HRESULT Terminal::UserResize(const COORD viewportSize) noexcept
[[nodiscard]] HRESULT Terminal::UserResize(const til::size viewportSize) noexcept
{
const auto oldDimensions = _GetMutableViewport().Dimensions();
if (viewportSize == oldDimensions)
@@ -263,7 +265,7 @@ std::wstring_view Terminal::GetWorkingDirectory()
if (_inAltBuffer())
{
// stash this resize for the future.
_deferredResize = til::size{ viewportSize };
_deferredResize = viewportSize;
_altBuffer->GetCursor().StartDeferDrawing();
// we're capturing `this` here because when we exit, we want to EndDefer on the (newly created) active buffer.
@@ -278,19 +280,19 @@ std::wstring_view Terminal::GetWorkingDirectory()
// Since the _mutableViewport is no longer the size of the actual
// viewport, then update our _altBufferSize tracker we're using to help
// us out here.
_altBufferSize = til::size{ viewportSize };
_altBufferSize = viewportSize;
return S_OK;
}
const auto dx = ::base::ClampSub(viewportSize.X, oldDimensions.X);
const short newBufferHeight = ::base::ClampAdd(viewportSize.Y, _scrollbackLines);
const auto dx = viewportSize.X - oldDimensions.X;
const auto newBufferHeight = std::clamp(viewportSize.Y + _scrollbackLines, 0, SHRT_MAX);
COORD bufferSize{ viewportSize.X, newBufferHeight };
til::size bufferSize{ viewportSize.X, newBufferHeight };
// This will be used to determine where the viewport should be in the new buffer.
const auto oldViewportTop = _mutableViewport.Top();
auto newViewportTop = oldViewportTop;
auto newVisibleTop = ::base::saturated_cast<short>(_VisibleStartIndex());
auto newVisibleTop = _VisibleStartIndex();
// If the original buffer had _no_ scroll offset, then we should be at the
// bottom in the new buffer as well. Track that case now.
@@ -334,7 +336,7 @@ std::wstring_view Terminal::GetWorkingDirectory()
oldRows.mutableViewportTop = oldViewportTop;
oldRows.visibleViewportTop = newVisibleTop;
const std::optional<short> oldViewStart{ oldViewportTop };
const std::optional oldViewStart{ oldViewportTop };
RETURN_IF_FAILED(TextBuffer::Reflow(*_mainBuffer.get(),
*newTextBuffer.get(),
_mutableViewport,
@@ -388,7 +390,7 @@ std::wstring_view Terminal::GetWorkingDirectory()
const auto maxRow = std::max(newLastChar.Y, newCursorPos.Y);
const short proposedTopFromLastLine = ::base::ClampAdd(::base::ClampSub(maxRow, viewportSize.Y), 1);
const auto proposedTopFromLastLine = maxRow - viewportSize.Y + 1;
const auto proposedTopFromScrollback = newViewportTop;
auto proposedTop = std::max(proposedTopFromLastLine,
@@ -438,7 +440,7 @@ std::wstring_view Terminal::GetWorkingDirectory()
// Make sure the proposed viewport is within the bounds of the buffer.
// First make sure the top is >=0
proposedTop = std::max(static_cast<short>(0), proposedTop);
proposedTop = std::max(0, proposedTop);
// If the new bottom would be below the bottom of the buffer, then slide the
// top up so that we'll still fit within the buffer.
@@ -457,7 +459,7 @@ std::wstring_view Terminal::GetWorkingDirectory()
// Make sure that we don't scroll past the mutableViewport at the bottom of the buffer
newVisibleTop = std::min(newVisibleTop, _mutableViewport.Top());
// Make sure we don't scroll past the top of the scrollback
newVisibleTop = std::max<short>(newVisibleTop, 0);
newVisibleTop = std::max(newVisibleTop, 0);
// If the old scrolloffset was 0, then we weren't scrolled back at all
// before, and shouldn't be now either.
@@ -560,7 +562,7 @@ bool Terminal::ShouldSendAlternateScroll(const unsigned int uiButton,
// - Given a coord, get the URI at that location
// Arguments:
// - The position
std::wstring Terminal::GetHyperlinkAtPosition(const COORD position)
std::wstring Terminal::GetHyperlinkAtPosition(const til::point position)
{
auto attr = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(position))->TextAttr();
if (attr.IsHyperlink())
@@ -576,8 +578,8 @@ std::wstring Terminal::GetHyperlinkAtPosition(const COORD position)
const auto end = result->stop;
std::wstring uri;
const auto startIter = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(start.to_win32_coord()));
const auto endIter = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(end.to_win32_coord()));
const auto startIter = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(start));
const auto endIter = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(end));
for (auto iter = startIter; iter != endIter; ++iter)
{
uri += iter->Chars();
@@ -593,7 +595,7 @@ std::wstring Terminal::GetHyperlinkAtPosition(const COORD position)
// - The position of the text
// Return value:
// - The hyperlink ID
uint16_t Terminal::GetHyperlinkIdAtPosition(const COORD position)
uint16_t Terminal::GetHyperlinkIdAtPosition(const til::point position)
{
return _activeBuffer().GetCellDataAt(_ConvertToBufferCell(position))->TextAttr().GetHyperlinkId();
}
@@ -604,9 +606,9 @@ uint16_t Terminal::GetHyperlinkIdAtPosition(const COORD position)
// - The position
// Return value:
// - The interval representing the start and end coordinates
std::optional<PointTree::interval> Terminal::GetHyperlinkIntervalFromPosition(const COORD position)
std::optional<PointTree::interval> Terminal::GetHyperlinkIntervalFromPosition(const til::point position)
{
const auto results = _patternIntervalTree.findOverlapping(til::point{ position.X + 1, position.Y }, til::point{ position });
const auto results = _patternIntervalTree.findOverlapping({ position.X + 1, position.Y }, position);
if (results.size() > 0)
{
for (const auto& result : results)
@@ -721,16 +723,14 @@ bool Terminal::SendKeyEvent(const WORD vkey,
// Return Value:
// - true if we translated the key event, and it should not be processed any further.
// - false if we did not translate the key, and it should be processed into a character.
bool Terminal::SendMouseEvent(const COORD viewportPos, const unsigned int uiButton, const ControlKeyStates states, const short wheelDelta, const TerminalInput::MouseButtonState state)
bool Terminal::SendMouseEvent(til::point viewportPos, const unsigned int uiButton, const ControlKeyStates states, const short wheelDelta, const TerminalInput::MouseButtonState state)
{
// GH#6401: VT applications should be able to receive mouse events from outside the
// terminal buffer. This is likely to happen when the user drags the cursor offscreen.
// We shouldn't throw away perfectly good events when they're offscreen, so we just
// clamp them to be within the range [(0, 0), (W, H)].
#pragma warning(suppress : 26496) // analysis can't tell we're assigning through a reference below
auto clampedPos{ viewportPos };
_GetMutableViewport().ToOrigin().Clamp(clampedPos);
return _terminalInput->HandleMouse(til::point{ clampedPos }, uiButton, GET_KEYSTATE_WPARAM(states.Value()), wheelDelta, state);
_GetMutableViewport().ToOrigin().Clamp(viewportPos);
return _terminalInput->HandleMouse(viewportPos, uiButton, GET_KEYSTATE_WPARAM(states.Value()), wheelDelta, state);
}
// Method Description:
@@ -757,6 +757,22 @@ bool Terminal::SendCharEvent(const wchar_t ch, const WORD scanCode, const Contro
vkey = _VirtualKeyFromCharacter(ch);
}
// GH#1527: When the user has auto mark prompts enabled, we're going to try
// and heuristically detect if this was the line the prompt was on.
// * If the key was an Enter keypress (Terminal.app also marks ^C keypresses
// as prompts. That's omitted for now.)
// * AND we're not in the alt buffer
//
// Then treat this line like it's a prompt mark.
if (_autoMarkPrompts && vkey == VK_RETURN && !_inAltBuffer())
{
DispatchTypes::ScrollMark mark;
mark.category = DispatchTypes::MarkCategory::Prompt;
// Don't set the color - we'll automatically use the DEFAULT_FOREGROUND
// color for any MarkCategory::Prompt marks without one set.
AddMark(mark);
}
// Unfortunately, the UI doesn't give us both a character down and a
// character up event, only a character received event. So fake sending both
// to the terminal input translator. Unless it's in win32-input-mode, it'll
@@ -789,8 +805,8 @@ void Terminal::_InvalidatePatternTree(interval_tree::IntervalTree<til::point, si
{
const auto vis = _VisibleStartIndex();
auto invalidate = [=](const PointTree::interval& interval) {
COORD startCoord{ gsl::narrow<SHORT>(interval.start.x), gsl::narrow<SHORT>(interval.start.y + vis) };
COORD endCoord{ gsl::narrow<SHORT>(interval.stop.x), gsl::narrow<SHORT>(interval.stop.y + vis) };
til::point startCoord{ interval.start.x, interval.start.y + vis };
til::point endCoord{ interval.stop.x, interval.stop.y + vis };
_InvalidateFromCoords(startCoord, endCoord);
};
tree.visit_all(invalidate);
@@ -800,30 +816,30 @@ void Terminal::_InvalidatePatternTree(interval_tree::IntervalTree<til::point, si
// - Given start and end coords, invalidates all the regions between them
// Arguments:
// - The start and end coords
void Terminal::_InvalidateFromCoords(const COORD start, const COORD end)
void Terminal::_InvalidateFromCoords(const til::point start, const til::point end)
{
if (start.Y == end.Y)
{
SMALL_RECT region{ start.X, start.Y, end.X, end.Y };
til::inclusive_rect region{ start.X, start.Y, end.X, end.Y };
_activeBuffer().TriggerRedraw(Viewport::FromInclusive(region));
}
else
{
const auto rowSize = gsl::narrow<SHORT>(_activeBuffer().GetRowByOffset(0).size());
const auto rowSize = _activeBuffer().GetRowByOffset(0).size();
// invalidate the first line
SMALL_RECT region{ start.X, start.Y, gsl::narrow<short>(rowSize - 1), gsl::narrow<short>(start.Y) };
til::inclusive_rect region{ start.X, start.Y, rowSize - 1, start.Y };
_activeBuffer().TriggerRedraw(Viewport::FromInclusive(region));
if ((end.Y - start.Y) > 1)
{
// invalidate the lines in between the first and last line
region = SMALL_RECT{ 0, start.Y + 1, gsl::narrow<short>(rowSize - 1), gsl::narrow<short>(end.Y - 1) };
region = til::inclusive_rect{ 0, start.Y + 1, rowSize - 1, end.Y - 1 };
_activeBuffer().TriggerRedraw(Viewport::FromInclusive(region));
}
// invalidate the last line
region = SMALL_RECT{ 0, end.Y, end.X, end.Y };
region = til::inclusive_rect{ 0, end.Y, end.X, end.Y };
_activeBuffer().TriggerRedraw(Viewport::FromInclusive(region));
}
}
@@ -968,16 +984,25 @@ WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept
#endif
}
// Method Description:
// - Get a reference to the the terminal's read/write lock.
// Return Value:
// - a ticket_lock which can be used to manually lock or unlock the terminal.
til::ticket_lock& Terminal::GetReadWriteLock() noexcept
{
return _readWriteLock;
}
Viewport Terminal::_GetMutableViewport() const noexcept
{
// GH#3493: if we're in the alt buffer, then it's possible that the mutable
// viewport's size hasn't been updated yet. In that case, use the
// temporarily stashed _altBufferSize instead.
return _inAltBuffer() ? Viewport::FromDimensions(_altBufferSize.to_win32_coord()) :
return _inAltBuffer() ? Viewport::FromDimensions(_altBufferSize) :
_mutableViewport;
}
short Terminal::GetBufferHeight() const noexcept
til::CoordType Terminal::GetBufferHeight() const noexcept
{
return _GetMutableViewport().BottomExclusive();
}
@@ -1011,8 +1036,8 @@ Viewport Terminal::_GetVisibleViewport() const noexcept
// GH#3493: if we're in the alt buffer, then it's possible that the mutable
// viewport's size hasn't been updated yet. In that case, use the
// temporarily stashed _altBufferSize instead.
const COORD origin{ 0, gsl::narrow<short>(_VisibleStartIndex()) };
const auto size{ _inAltBuffer() ? _altBufferSize.to_win32_coord() :
const til::point origin{ 0, _VisibleStartIndex() };
const auto size{ _inAltBuffer() ? _altBufferSize :
_mutableViewport.Dimensions() };
return Viewport::FromDimensions(origin,
size);
@@ -1056,7 +1081,7 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView)
{
// If "wch" was a surrogate character, we just consumed 2 code units above.
// -> Increment "i" by 1 in that case and thus by 2 in total in this iteration.
proposedCursorPosition.X += gsl::narrow<SHORT>(cellDistance);
proposedCursorPosition.X += cellDistance;
i += inputDistance - 1;
}
else
@@ -1095,7 +1120,7 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView)
cursor.EndDeferDrawing();
}
void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
void Terminal::_AdjustCursorPosition(const til::point proposedPosition)
{
#pragma warning(suppress : 26496) // cpp core checks wants this const but it's modified below.
auto proposedCursorPosition = proposedPosition;
@@ -1104,7 +1129,7 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
// If we're about to scroll past the bottom of the buffer, instead cycle the
// buffer.
SHORT rowsPushedOffTopOfBuffer = 0;
til::CoordType rowsPushedOffTopOfBuffer = 0;
const auto newRows = std::max(0, proposedCursorPosition.Y - bufferSize.Height() + 1);
if (proposedCursorPosition.Y >= bufferSize.Height())
{
@@ -1159,7 +1184,7 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
// In the alt buffer, we never need to adjust _mutableViewport, which is the viewport of the main buffer.
if (newViewTop != _mutableViewport.Top())
{
_mutableViewport = Viewport::FromDimensions({ 0, gsl::narrow<short>(newViewTop) },
_mutableViewport = Viewport::FromDimensions({ 0, newViewTop },
_mutableViewport.Dimensions());
updatedViewport = true;
}
@@ -1196,10 +1221,21 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
if (rowsPushedOffTopOfBuffer != 0)
{
if (_scrollMarks.size() > 0)
{
for (auto& mark : _scrollMarks)
{
mark.start.y -= rowsPushedOffTopOfBuffer;
}
_scrollMarks.erase(std::remove_if(_scrollMarks.begin(),
_scrollMarks.end(),
[](const VirtualTerminal::DispatchTypes::ScrollMark& m) { return m.start.y < 0; }),
_scrollMarks.end());
}
// We have to report the delta here because we might have circled the text buffer.
// That didn't change the viewport and therefore the TriggerScroll(void)
// method can't detect the delta on its own.
COORD delta{ 0, gsl::narrow_cast<short>(-rowsPushedOffTopOfBuffer) };
til::point delta{ 0, -rowsPushedOffTopOfBuffer };
_activeBuffer().TriggerScroll(delta);
}
}
@@ -1273,11 +1309,6 @@ void Terminal::SetTitleChangedCallback(std::function<void(std::wstring_view)> pf
_pfnTitleChanged.swap(pfn);
}
void Terminal::SetTabColorChangedCallback(std::function<void(const std::optional<til::color>)> pfn) noexcept
{
_pfnTabColorChanged.swap(pfn);
}
void Terminal::SetCopyToClipboardCallback(std::function<void(std::wstring_view)> pfn) noexcept
{
_pfnCopyToClipboard.swap(pfn);
@@ -1312,6 +1343,15 @@ void Terminal::SetShowWindowCallback(std::function<void(bool)> pfn) noexcept
_pfnShowWindowChanged.swap(pfn);
}
// Method Description:
// - Allows setting a callback for playing MIDI notes.
// Arguments:
// - pfn: a function callback that takes a note number, a velocity level, and a duration
void Terminal::SetPlayMidiNoteCallback(std::function<void(const int, const int, const std::chrono::microseconds)> pfn) noexcept
{
_pfnPlayMidiNote.swap(pfn);
}
// Method Description:
// - Sets the cursor to be currently on. On/Off is tracked independently of
// cursor visibility (hidden/visible). On/off is controlled by the cursor
@@ -1329,7 +1369,7 @@ void Terminal::SetCursorOn(const bool isOn)
bool Terminal::IsCursorBlinkingAllowed() const noexcept
{
const auto& cursor = _activeBuffer().GetCursor();
return cursor.IsBlinkingAllowed();
return !_markMode && cursor.IsBlinkingAllowed();
}
// Method Description:
@@ -1358,10 +1398,18 @@ void Terminal::ClearPatternTree() noexcept
// Method Description:
// - Returns the tab color
// If the starting color exits, it's value is preferred
// If the starting color exists, its value is preferred
const std::optional<til::color> Terminal::GetTabColor() const noexcept
{
return _startingTabColor.has_value() ? _startingTabColor : _tabColor;
if (_startingTabColor.has_value())
{
return _startingTabColor;
}
else
{
const auto tabColor = _renderSettings.GetColorAlias(ColorAlias::FrameBackground);
return tabColor == INVALID_COLOR ? std::nullopt : std::optional<til::color>{ tabColor };
}
}
// Method Description:
@@ -1436,6 +1484,11 @@ void Terminal::ApplyScheme(const Scheme& colorScheme)
_renderSettings.SetColorTableEntry(TextColor::CURSOR_COLOR, til::color{ colorScheme.CursorColor });
_renderSettings.MakeAdjustedColorArray();
// Tell the control that the scrollbar has somehow changed. Used as a
// workaround to force the control to redraw any scrollbar marks whose color
// may have changed.
_NotifyScrollEvent();
}
bool Terminal::_inAltBuffer() const noexcept
@@ -1463,11 +1516,100 @@ void Terminal::_updateUrlDetection()
}
}
// Method Description:
// - Returns the position of the cursor relative to the active viewport
til::point Terminal::GetViewportRelativeCursorPosition() const noexcept
void Terminal::AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark,
const til::point& start,
const til::point& end)
{
const til::point absoluteCursorPosition{ GetCursorPosition() };
const auto viewport{ _GetMutableViewport() };
return absoluteCursorPosition - til::point{ viewport.Origin() };
if (_inAltBuffer())
{
return;
}
DispatchTypes::ScrollMark m = mark;
m.start = start;
m.end = end;
_scrollMarks.push_back(m);
// Tell the control that the scrollbar has somehow changed. Used as a
// workaround to force the control to redraw any scrollbar marks
_NotifyScrollEvent();
}
void Terminal::ClearMark()
{
// Look for one where the cursor is, or where the selection is if we have
// one. Any mark that intersects the cursor/selection, on either side
// (inclusive), will get cleared.
const til::point cursor{ _activeBuffer().GetCursor().GetPosition() };
til::point start{ cursor };
til::point end{ cursor };
if (IsSelectionActive())
{
start = til::point{ GetSelectionAnchor() };
end = til::point{ GetSelectionEnd() };
}
_scrollMarks.erase(std::remove_if(_scrollMarks.begin(),
_scrollMarks.end(),
[&start, &end](const auto& m) {
return (m.start >= start && m.start <= end) ||
(m.end >= start && m.end <= end);
}),
_scrollMarks.end());
// Tell the control that the scrollbar has somehow changed. Used as a
// workaround to force the control to redraw any scrollbar marks
_NotifyScrollEvent();
}
void Terminal::ClearAllMarks()
{
_scrollMarks.clear();
// Tell the control that the scrollbar has somehow changed. Used as a
// workaround to force the control to redraw any scrollbar marks
_NotifyScrollEvent();
}
const std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark>& Terminal::GetScrollMarks() const
{
// TODO: GH#11000 - when the marks are stored per-buffer, get rid of this.
// We want to return _no_ marks when we're in the alt buffer, to effectively
// hide them. We need to return a reference, so we can't just ctor an empty
// list here just for when we're in the alt buffer.
static std::vector<DispatchTypes::ScrollMark> _altBufferMarks{};
return _inAltBuffer() ? _altBufferMarks : _scrollMarks;
}
til::color Terminal::GetColorForMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) const
{
if (mark.color.has_value())
{
return *mark.color;
}
switch (mark.category)
{
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Prompt:
{
return _renderSettings.GetColorAlias(ColorAlias::DefaultForeground);
}
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Error:
{
return _renderSettings.GetColorTableEntry(TextColor::BRIGHT_RED);
}
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Warning:
{
return _renderSettings.GetColorTableEntry(TextColor::BRIGHT_YELLOW);
}
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Success:
{
return _renderSettings.GetColorTableEntry(TextColor::BRIGHT_GREEN);
}
default:
case Microsoft::Console::VirtualTerminal::DispatchTypes::MarkCategory::Info:
{
return _renderSettings.GetColorAlias(ColorAlias::DefaultForeground);
}
}
}

View File

@@ -69,8 +69,8 @@ public:
Terminal& operator=(const Terminal&) = default;
Terminal& operator=(Terminal&&) = default;
void Create(COORD viewportSize,
SHORT scrollbackLines,
void Create(til::size viewportSize,
til::CoordType scrollbackLines,
Microsoft::Console::Render::Renderer& renderer);
void CreateFromSettings(winrt::Microsoft::Terminal::Core::ICoreSettings settings,
@@ -84,8 +84,6 @@ public:
bool IsXtermBracketedPasteModeEnabled() const;
std::wstring_view GetWorkingDirectory();
til::point GetViewportRelativeCursorPosition() const noexcept;
// Write comes from the PTY and goes to our parser to be stored in the output buffer
void Write(std::wstring_view stringView);
@@ -94,8 +92,9 @@ public:
[[nodiscard]] std::unique_lock<til::ticket_lock> LockForReading();
[[nodiscard]] std::unique_lock<til::ticket_lock> LockForWriting();
til::ticket_lock& GetReadWriteLock() noexcept;
short GetBufferHeight() const noexcept;
til::CoordType GetBufferHeight() const noexcept;
int ViewStartIndex() const noexcept;
int ViewEndIndex() const noexcept;
@@ -103,6 +102,11 @@ public:
RenderSettings& GetRenderSettings() noexcept { return _renderSettings; };
const RenderSettings& GetRenderSettings() const noexcept { return _renderSettings; };
const std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark>& GetScrollMarks() const;
void AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark,
const til::point& start,
const til::point& end);
#pragma region ITerminalApi
// These methods are defined in TerminalApi.cpp
void PrintString(const std::wstring_view string) override;
@@ -119,28 +123,36 @@ public:
void LineFeed(const bool withReturn) override;
void SetWindowTitle(const std::wstring_view title) override;
CursorType GetUserDefaultCursorStyle() const override;
bool ResizeWindow(const size_t width, const size_t height) override;
bool ResizeWindow(const til::CoordType width, const til::CoordType height) override;
void SetConsoleOutputCP(const unsigned int codepage) override;
unsigned int GetConsoleOutputCP() const override;
void EnableXtermBracketedPasteMode(const bool enabled) override;
void CopyToClipboard(std::wstring_view content) override;
void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
void SetWorkingDirectory(std::wstring_view uri) override;
void PlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) override;
void ShowWindow(bool showOrHide) override;
void UseAlternateScreenBuffer() override;
void UseMainScreenBuffer() override;
void AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) override;
bool IsConsolePty() const override;
bool IsVtInputEnabled() const override;
void NotifyAccessibilityChange(const til::rect& changedRect) override;
#pragma endregion
void ClearMark();
void ClearAllMarks();
til::color GetColorForMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark) const;
#pragma region ITerminalInput
// These methods are defined in Terminal.cpp
bool SendKeyEvent(const WORD vkey, const WORD scanCode, const Microsoft::Terminal::Core::ControlKeyStates states, const bool keyDown) override;
bool SendMouseEvent(const COORD viewportPos, const unsigned int uiButton, const ControlKeyStates states, const short wheelDelta, const Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState state) override;
bool SendMouseEvent(const til::point viewportPos, const unsigned int uiButton, const ControlKeyStates states, const short wheelDelta, const Microsoft::Console::VirtualTerminal::TerminalInput::MouseButtonState state) override;
bool SendCharEvent(const wchar_t ch, const WORD scanCode, const ControlKeyStates states) override;
[[nodiscard]] HRESULT UserResize(const COORD viewportSize) noexcept override;
[[nodiscard]] HRESULT UserResize(const til::size viewportSize) noexcept override;
void UserScrollViewport(const int viewTop) override;
int GetScrollOffset() noexcept override;
@@ -150,14 +162,14 @@ public:
void FocusChanged(const bool focused) noexcept override;
std::wstring GetHyperlinkAtPosition(const COORD position);
uint16_t GetHyperlinkIdAtPosition(const COORD position);
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> GetHyperlinkIntervalFromPosition(const COORD position);
std::wstring GetHyperlinkAtPosition(const til::point position);
uint16_t GetHyperlinkIdAtPosition(const til::point position);
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> GetHyperlinkIntervalFromPosition(const til::point position);
#pragma endregion
#pragma region IBaseData(base to IRenderData and IUiaData)
Microsoft::Console::Types::Viewport GetViewport() noexcept override;
COORD GetTextBufferEndPosition() const noexcept override;
til::point GetTextBufferEndPosition() const noexcept override;
const TextBuffer& GetTextBuffer() const noexcept override;
const FontInfo& GetFontInfo() const noexcept override;
@@ -167,7 +179,7 @@ public:
#pragma region IRenderData
// These methods are defined in TerminalRenderData.cpp
COORD GetCursorPosition() const noexcept override;
til::point GetCursorPosition() const noexcept override;
bool IsCursorVisible() const noexcept override;
bool IsCursorOn() const noexcept override;
ULONG GetCursorHeight() const noexcept override;
@@ -178,7 +190,7 @@ public:
const bool IsGridLineDrawingAllowed() noexcept override;
const std::wstring GetHyperlinkUri(uint16_t id) const noexcept override;
const std::wstring GetHyperlinkCustomId(uint16_t id) const noexcept override;
const std::vector<size_t> GetPatternId(const COORD location) const noexcept override;
const std::vector<size_t> GetPatternId(const til::point location) const noexcept override;
#pragma endregion
#pragma region IUiaData
@@ -187,23 +199,23 @@ public:
const bool IsSelectionActive() const noexcept override;
const bool IsBlockSelection() const noexcept override;
void ClearSelection() override;
void SelectNewRegion(const COORD coordStart, const COORD coordEnd) override;
const COORD GetSelectionAnchor() const noexcept override;
const COORD GetSelectionEnd() const noexcept override;
void SelectNewRegion(const til::point coordStart, const til::point coordEnd) override;
const til::point GetSelectionAnchor() const noexcept override;
const til::point GetSelectionEnd() const noexcept override;
const std::wstring_view GetConsoleTitle() const noexcept override;
void ColorSelection(const COORD coordSelectionStart, const COORD coordSelectionEnd, const TextAttribute) override;
void ColorSelection(const til::point coordSelectionStart, const til::point coordSelectionEnd, const TextAttribute) override;
const bool IsUiaDataInitialized() const noexcept override;
#pragma endregion
void SetWriteInputCallback(std::function<void(std::wstring_view)> pfn) noexcept;
void SetWarningBellCallback(std::function<void()> pfn) noexcept;
void SetTitleChangedCallback(std::function<void(std::wstring_view)> pfn) noexcept;
void SetTabColorChangedCallback(std::function<void(const std::optional<til::color>)> pfn) noexcept;
void SetCopyToClipboardCallback(std::function<void(std::wstring_view)> pfn) noexcept;
void SetScrollPositionChangedCallback(std::function<void(const int, const int, const int)> pfn) noexcept;
void SetCursorPositionChangedCallback(std::function<void()> pfn) noexcept;
void TaskbarProgressChangedCallback(std::function<void()> pfn) noexcept;
void SetShowWindowCallback(std::function<void(bool)> pfn) noexcept;
void SetPlayMidiNoteCallback(std::function<void(const int, const int, const std::chrono::microseconds)> pfn) noexcept;
void SetCursorOn(const bool isOn);
bool IsCursorBlinkingAllowed() const noexcept;
@@ -237,16 +249,17 @@ public:
Viewport,
Buffer
};
void MultiClickSelection(const COORD viewportPos, SelectionExpansion expansionMode);
void SetSelectionAnchor(const COORD position);
void SetSelectionEnd(const COORD position, std::optional<SelectionExpansion> newExpansionMode = std::nullopt);
void MultiClickSelection(const til::point viewportPos, SelectionExpansion expansionMode);
void SetSelectionAnchor(const til::point position);
void SetSelectionEnd(const til::point position, std::optional<SelectionExpansion> newExpansionMode = std::nullopt);
void SetBlockSelection(const bool isEnabled) noexcept;
void UpdateSelection(SelectionDirection direction, SelectionExpansion mode);
void UpdateSelection(SelectionDirection direction, SelectionExpansion mode, ControlKeyStates mods);
void SelectAll();
bool IsInQuickEditMode() const noexcept;
bool IsInMarkMode() const;
void ToggleMarkMode();
using UpdateSelectionParams = std::optional<std::pair<SelectionDirection, SelectionExpansion>>;
static UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey);
UpdateSelectionParams ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const;
const TextBuffer::TextAndColor RetrieveSelectedTextFromBuffer(bool trimTrailingWhitespace);
#pragma endregion
@@ -270,9 +283,9 @@ private:
std::function<void(const int, const int, const int)> _pfnScrollPositionChanged;
std::function<void()> _pfnCursorPositionChanged;
std::function<void(const std::optional<til::color>)> _pfnTabColorChanged;
std::function<void()> _pfnTaskbarProgressChanged;
std::function<void(bool)> _pfnShowWindowChanged;
std::function<void(const int, const int, const std::chrono::microseconds)> _pfnPlayMidiNote;
RenderSettings _renderSettings;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
@@ -280,7 +293,6 @@ private:
std::optional<std::wstring> _title;
std::wstring _startingTitle;
std::optional<til::color> _tabColor;
std::optional<til::color> _startingTabColor;
CursorType _defaultCursorShape;
@@ -290,6 +302,7 @@ private:
bool _suppressApplicationTitle;
bool _bracketedPasteMode;
bool _trimBlockSelection;
bool _autoMarkPrompts;
size_t _taskbarState;
size_t _taskbarProgress;
@@ -303,26 +316,26 @@ private:
FontInfo _fontInfo{ DEFAULT_FONT_FACE, TMPF_TRUETYPE, 10, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false };
#pragma region Text Selection
// a selection is represented as a range between two COORDs (start and end)
// the pivot is the COORD that remains selected when you extend a selection in any direction
// the pivot is the til::point that remains selected when you extend a selection in any direction
// this is particularly useful when a word selection is extended over its starting point
// see TerminalSelection.cpp for more information
struct SelectionAnchors
{
COORD start;
COORD end;
COORD pivot;
til::point start;
til::point end;
til::point pivot;
};
std::optional<SelectionAnchors> _selection;
bool _blockSelection;
std::wstring _wordDelimiters;
SelectionExpansion _multiClickSelectionMode;
bool _quickEditMode;
bool _markMode;
#pragma endregion
std::unique_ptr<TextBuffer> _mainBuffer;
std::unique_ptr<TextBuffer> _altBuffer;
Microsoft::Console::Types::Viewport _mutableViewport;
SHORT _scrollbackLines;
til::CoordType _scrollbackLines;
bool _detectURLs{ false };
til::size _altBufferSize;
@@ -346,7 +359,7 @@ private:
interval_tree::IntervalTree<til::point, size_t> _patternIntervalTree;
void _InvalidatePatternTree(interval_tree::IntervalTree<til::point, size_t>& tree);
void _InvalidateFromCoords(const COORD start, const COORD end);
void _InvalidateFromCoords(const til::point start, const til::point end);
// Since virtual keys are non-zero, you assume that this field is empty/invalid if it is.
struct KeyEventCodes
@@ -356,6 +369,8 @@ private:
};
std::optional<KeyEventCodes> _lastKeyEventCodes;
std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark> _scrollMarks;
static WORD _ScanCodeFromVirtualKey(const WORD vkey) noexcept;
static WORD _VirtualKeyFromScanCode(const WORD scanCode) noexcept;
static WORD _VirtualKeyFromCharacter(const wchar_t ch) noexcept;
@@ -372,7 +387,7 @@ private:
void _WriteBuffer(const std::wstring_view& stringView);
void _AdjustCursorPosition(const COORD proposedPosition);
void _AdjustCursorPosition(const til::point proposedPosition);
void _NotifyScrollEvent() noexcept;
@@ -384,14 +399,14 @@ private:
#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
std::vector<SMALL_RECT> _GetSelectionRects() const noexcept;
std::pair<COORD, COORD> _PivotSelection(const COORD targetPos, bool& targetStart) const;
std::pair<COORD, COORD> _ExpandSelectionAnchors(std::pair<COORD, COORD> anchors) const;
COORD _ConvertToBufferCell(const COORD viewportPos) const;
void _MoveByChar(SelectionDirection direction, COORD& pos);
void _MoveByWord(SelectionDirection direction, COORD& pos);
void _MoveByViewport(SelectionDirection direction, COORD& pos);
void _MoveByBuffer(SelectionDirection direction, COORD& pos);
std::vector<til::inclusive_rect> _GetSelectionRects() const noexcept;
std::pair<til::point, til::point> _PivotSelection(const til::point targetPos, bool& targetStart) const;
std::pair<til::point, til::point> _ExpandSelectionAnchors(std::pair<til::point, til::point> anchors) const;
til::point _ConvertToBufferCell(const til::point viewportPos) const;
void _MoveByChar(SelectionDirection direction, til::point& pos);
void _MoveByWord(SelectionDirection direction, til::point& pos);
void _MoveByViewport(SelectionDirection direction, til::point& pos);
void _MoveByBuffer(SelectionDirection direction, til::point& pos);
#pragma endregion
#ifdef UNIT_TESTING

View File

@@ -45,7 +45,7 @@ void Terminal::SetViewportPosition(const til::point position)
if (!_inAltBuffer())
{
const auto dimensions = _GetMutableViewport().Dimensions();
_mutableViewport = Viewport::FromDimensions(position.to_win32_coord(), dimensions);
_mutableViewport = Viewport::FromDimensions(position, dimensions);
Terminal::_NotifyScrollEvent();
}
}
@@ -106,7 +106,7 @@ CursorType Terminal::GetUserDefaultCursorStyle() const
return _defaultCursorShape;
}
bool Terminal::ResizeWindow(const size_t /*width*/, const size_t /*height*/)
bool Terminal::ResizeWindow(const til::CoordType /*width*/, const til::CoordType /*height*/)
{
// TODO: This will be needed to support various resizing sequences. See also GH#1860.
return false;
@@ -188,10 +188,15 @@ void Terminal::SetWorkingDirectory(std::wstring_view uri)
_workingDirectory = uri;
}
void Terminal::PlayMidiNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration)
{
_pfnPlayMidiNote(noteNumber, velocity, duration);
}
void Terminal::UseAlternateScreenBuffer()
{
// the new alt buffer is exactly the size of the viewport.
_altBufferSize = til::size{ _mutableViewport.Dimensions() };
_altBufferSize = _mutableViewport.Dimensions();
const auto cursorSize = _mainBuffer->GetCursor().GetSize();
@@ -199,7 +204,7 @@ void Terminal::UseAlternateScreenBuffer()
_mainBuffer->ClearPatternRecognizers();
// Create a new alt buffer
_altBuffer = std::make_unique<TextBuffer>(_altBufferSize.to_win32_coord(),
_altBuffer = std::make_unique<TextBuffer>(_altBufferSize,
TextAttribute{},
cursorSize,
true,
@@ -270,7 +275,7 @@ void Terminal::UseMainScreenBuffer()
if (_deferredResize.has_value())
{
LOG_IF_FAILED(UserResize(_deferredResize.value().to_win32_coord()));
LOG_IF_FAILED(UserResize(_deferredResize.value()));
_deferredResize = std::nullopt;
}
@@ -293,6 +298,12 @@ void Terminal::UseMainScreenBuffer()
CATCH_LOG();
}
void Terminal::AddMark(const Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark& mark)
{
const til::point cursorPos{ _activeBuffer().GetCursor().GetPosition() };
AddMark(mark, cursorPos, cursorPos);
}
// Method Description:
// - Reacts to a client asking us to show or hide the window.
// Arguments:

View File

@@ -43,9 +43,9 @@ using namespace Microsoft::Terminal::Core;
// - Helper to determine the selected region of the buffer. Used for rendering.
// Return Value:
// - A vector of rectangles representing the regions to select, line by line. They are absolute coordinates relative to the buffer origin.
std::vector<SMALL_RECT> Terminal::_GetSelectionRects() const noexcept
std::vector<til::inclusive_rect> Terminal::_GetSelectionRects() const noexcept
{
std::vector<SMALL_RECT> result;
std::vector<til::inclusive_rect> result;
if (!IsSelectionActive())
{
@@ -66,7 +66,7 @@ std::vector<SMALL_RECT> Terminal::_GetSelectionRects() const noexcept
// - None
// Return Value:
// - None
const COORD Terminal::GetSelectionAnchor() const noexcept
const til::point Terminal::GetSelectionAnchor() const noexcept
{
return _selection->start;
}
@@ -77,7 +77,7 @@ const COORD Terminal::GetSelectionAnchor() const noexcept
// - None
// Return Value:
// - None
const COORD Terminal::GetSelectionEnd() const noexcept
const til::point Terminal::GetSelectionEnd() const noexcept
{
return _selection->end;
}
@@ -96,17 +96,12 @@ const bool Terminal::IsBlockSelection() const noexcept
return _blockSelection;
}
bool Terminal::IsInQuickEditMode() const noexcept
{
return _quickEditMode;
}
// Method Description:
// - Perform a multi-click selection at viewportPos expanding according to the expansionMode
// Arguments:
// - viewportPos: the (x,y) coordinate on the visible viewport
// - expansionMode: the SelectionExpansion to dictate the boundaries of the selection anchors
void Terminal::MultiClickSelection(const COORD viewportPos, SelectionExpansion expansionMode)
void Terminal::MultiClickSelection(const til::point viewportPos, SelectionExpansion expansionMode)
{
// set the selection pivot to expand the selection using SetSelectionEnd()
_selection = SelectionAnchors{};
@@ -124,7 +119,7 @@ void Terminal::MultiClickSelection(const COORD viewportPos, SelectionExpansion e
// - Record the position of the beginning of a selection
// Arguments:
// - position: the (x,y) coordinate on the visible viewport
void Terminal::SetSelectionAnchor(const COORD viewportPos)
void Terminal::SetSelectionAnchor(const til::point viewportPos)
{
_selection = SelectionAnchors{};
_selection->pivot = _ConvertToBufferCell(viewportPos);
@@ -141,7 +136,7 @@ void Terminal::SetSelectionAnchor(const COORD viewportPos)
// Arguments:
// - viewportPos: the (x,y) coordinate on the visible viewport
// - newExpansionMode: overwrites the _multiClickSelectionMode for this function call. Used for ShiftClick
void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional<SelectionExpansion> newExpansionMode)
void Terminal::SetSelectionEnd(const til::point viewportPos, std::optional<SelectionExpansion> newExpansionMode)
{
if (!_selection.has_value())
{
@@ -185,7 +180,7 @@ void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional<SelectionE
// - targetStart: if true, target will be the new start. Otherwise, target will be the new end.
// Return Value:
// - the new start/end for a selection
std::pair<COORD, COORD> Terminal::_PivotSelection(const COORD targetPos, bool& targetStart) const
std::pair<til::point, til::point> Terminal::_PivotSelection(const til::point targetPos, bool& targetStart) const
{
if (targetStart = _activeBuffer().GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0)
{
@@ -207,7 +202,7 @@ std::pair<COORD, COORD> Terminal::_PivotSelection(const COORD targetPos, bool& t
// - anchors: a pair of selection anchors representing a desired selection
// Return Value:
// - the new start/end for a selection
std::pair<COORD, COORD> Terminal::_ExpandSelectionAnchors(std::pair<COORD, COORD> anchors) const
std::pair<til::point, til::point> Terminal::_ExpandSelectionAnchors(std::pair<til::point, til::point> anchors) const
{
auto start = anchors.first;
auto end = anchors.second;
@@ -240,13 +235,41 @@ void Terminal::SetBlockSelection(const bool isEnabled) noexcept
_blockSelection = isEnabled;
}
Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey)
bool Terminal::IsInMarkMode() const
{
if (mods.IsShiftPressed() && !mods.IsAltPressed())
return _markMode;
}
void Terminal::ToggleMarkMode()
{
if (_markMode)
{
// Exit Mark Mode
ClearSelection();
}
else
{
// Enter Mark Mode
// NOTE: directly set cursor state. We already should have locked before calling this function.
_activeBuffer().GetCursor().SetIsOn(false);
const auto cursorPos{ _activeBuffer().GetCursor().GetPosition() };
_selection = SelectionAnchors{};
_selection->start = cursorPos;
_selection->end = cursorPos;
_selection->pivot = cursorPos;
_markMode = true;
_blockSelection = false;
}
}
Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams(const ControlKeyStates mods, const WORD vkey) const
{
if ((_markMode || mods.IsShiftPressed()) && !mods.IsAltPressed())
{
if (mods.IsCtrlPressed())
{
// Ctrl + Shift + _
// (Mark Mode) Ctrl + _
switch (vkey)
{
case VK_LEFT:
@@ -262,6 +285,7 @@ Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams
else
{
// Shift + _
// (Mark Mode) Just the vkeys
switch (vkey)
{
case VK_HOME:
@@ -286,14 +310,22 @@ Terminal::UpdateSelectionParams Terminal::ConvertKeyEventToUpdateSelectionParams
return std::nullopt;
}
void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode)
// Method Description:
// - updates the selection endpoints based on a direction and expansion mode. Primarily used for keyboard selection.
// Arguments:
// - direction: the direction to move the selection endpoint in
// - mode: the type of movement to be performed (i.e. move by word)
// - mods: the key modifiers pressed when performing this update
void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion mode, ControlKeyStates mods)
{
// 1. Figure out which endpoint to update
// One of the endpoints is the pivot, signifying that the other endpoint is the one we want to move.
const auto movingEnd{ _selection->start == _selection->pivot };
// If we're in mark mode, shift dictates whether you are moving the end or not.
// Otherwise, we're updating an existing selection, so one of the endpoints is the pivot,
// signifying that the other endpoint is the one we want to move.
const auto movingEnd{ _markMode ? mods.IsShiftPressed() : _selection->start == _selection->pivot };
auto targetPos{ movingEnd ? _selection->end : _selection->start };
// 2 Perform the movement
// 2. Perform the movement
switch (mode)
{
case SelectionExpansion::Char:
@@ -312,14 +344,28 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion
// 3. Actually modify the selection
// NOTE: targetStart doesn't matter here
auto targetStart = false;
_quickEditMode = true;
std::tie(_selection->start, _selection->end) = _PivotSelection(targetPos, targetStart);
if (_markMode)
{
// [Mark Mode]
// - moveSelectionEnd --> just move end (i.e. shift + arrow keys)
// - !moveSelectionEnd --> move all three (i.e. just use arrow keys)
_selection->end = targetPos;
if (!movingEnd)
{
_selection->start = targetPos;
_selection->pivot = targetPos;
}
}
else
{
auto targetStart = false;
std::tie(_selection->start, _selection->end) = _PivotSelection(targetPos, targetStart);
}
// 4. Scroll (if necessary)
if (const auto visibleViewport = _GetVisibleViewport(); !visibleViewport.IsInBounds(targetPos))
if (const auto viewport = _GetVisibleViewport(); !viewport.IsInBounds(targetPos))
{
if (const auto amtAboveView = visibleViewport.Top() - targetPos.Y; amtAboveView > 0)
if (const auto amtAboveView = viewport.Top() - targetPos.Y; amtAboveView > 0)
{
// anchor is above visible viewport, scroll by that amount
_scrollOffset += amtAboveView;
@@ -327,7 +373,7 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion
else
{
// anchor is below visible viewport, scroll by that amount
const auto amtBelowView = targetPos.Y - visibleViewport.BottomInclusive();
const auto amtBelowView = targetPos.Y - viewport.BottomInclusive();
_scrollOffset -= amtBelowView;
}
_NotifyScrollEvent();
@@ -344,41 +390,39 @@ void Terminal::SelectAll()
_selection->pivot = _selection->end;
}
void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos)
void Terminal::_MoveByChar(SelectionDirection direction, til::point& pos)
{
switch (direction)
{
case SelectionDirection::Left:
_activeBuffer().GetSize().DecrementInBounds(pos);
pos = _activeBuffer().GetGlyphStart(til::point{ pos }).to_win32_coord();
pos = _activeBuffer().GetGlyphStart(pos);
break;
case SelectionDirection::Right:
_activeBuffer().GetSize().IncrementInBounds(pos);
pos = _activeBuffer().GetGlyphEnd(til::point{ pos }).to_win32_coord();
pos = _activeBuffer().GetGlyphEnd(pos);
break;
case SelectionDirection::Up:
{
const auto bufferSize{ _activeBuffer().GetSize() };
const auto newY{ base::ClampSub<short, short>(pos.Y, 1).RawValue() };
pos = newY < bufferSize.Top() ? bufferSize.Origin() : COORD{ pos.X, newY };
pos = { pos.X, std::clamp(pos.Y - 1, bufferSize.Top(), bufferSize.BottomInclusive()) };
break;
}
case SelectionDirection::Down:
{
const auto bufferSize{ _activeBuffer().GetSize() };
const auto mutableBottom{ _GetMutableViewport().BottomInclusive() };
const auto newY{ base::ClampAdd<short, short>(pos.Y, 1).RawValue() };
pos = newY > mutableBottom ? COORD{ bufferSize.RightInclusive(), mutableBottom } : COORD{ pos.X, newY };
pos = { pos.X, std::clamp(pos.Y + 1, bufferSize.Top(), bufferSize.BottomInclusive()) };
break;
}
}
}
void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos)
void Terminal::_MoveByWord(SelectionDirection direction, til::point& pos)
{
switch (direction)
{
case SelectionDirection::Left:
{
const auto wordStartPos{ _activeBuffer().GetWordStart(pos, _wordDelimiters) };
if (_activeBuffer().GetSize().CompareInBounds(_selection->pivot, pos) < 0)
{
@@ -399,7 +443,9 @@ void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos)
pos = wordStartPos;
}
break;
}
case SelectionDirection::Right:
{
const auto wordEndPos{ _activeBuffer().GetWordEnd(pos, _wordDelimiters) };
if (_activeBuffer().GetSize().CompareInBounds(pos, _selection->pivot) < 0)
{
@@ -420,6 +466,7 @@ void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos)
pos = wordEndPos;
}
break;
}
case SelectionDirection::Up:
_MoveByChar(direction, pos);
pos = _activeBuffer().GetWordStart(pos, _wordDelimiters);
@@ -431,7 +478,7 @@ void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos)
}
}
void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos)
void Terminal::_MoveByViewport(SelectionDirection direction, til::point& pos)
{
const auto bufferSize{ _activeBuffer().GetSize() };
switch (direction)
@@ -445,22 +492,22 @@ void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos)
case SelectionDirection::Up:
{
const auto viewportHeight{ _GetMutableViewport().Height() };
const auto newY{ base::ClampSub<short, short>(pos.Y, viewportHeight) };
pos = newY < bufferSize.Top() ? bufferSize.Origin() : COORD{ pos.X, newY };
const auto newY{ pos.Y - viewportHeight };
pos = newY < bufferSize.Top() ? bufferSize.Origin() : til::point{ pos.X, newY };
break;
}
case SelectionDirection::Down:
{
const auto viewportHeight{ _GetMutableViewport().Height() };
const auto mutableBottom{ _GetMutableViewport().BottomInclusive() };
const auto newY{ base::ClampAdd<short, short>(pos.Y, viewportHeight) };
pos = newY > mutableBottom ? COORD{ bufferSize.RightInclusive(), mutableBottom } : COORD{ pos.X, newY };
const auto newY{ pos.Y + viewportHeight };
pos = newY > mutableBottom ? til::point{ bufferSize.RightInclusive(), mutableBottom } : til::point{ pos.X, newY };
break;
}
}
}
void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos)
void Terminal::_MoveByBuffer(SelectionDirection direction, til::point& pos)
{
const auto bufferSize{ _activeBuffer().GetSize() };
switch (direction)
@@ -482,7 +529,7 @@ void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos)
void Terminal::ClearSelection()
{
_selection = std::nullopt;
_quickEditMode = false;
_markMode = false;
}
// Method Description:
@@ -517,10 +564,10 @@ const TextBuffer::TextAndColor Terminal::RetrieveSelectedTextFromBuffer(bool sin
// - viewportPos: a coordinate on the viewport
// Return Value:
// - the corresponding location on the buffer
COORD Terminal::_ConvertToBufferCell(const COORD viewportPos) const
til::point Terminal::_ConvertToBufferCell(const til::point viewportPos) const
{
const auto yPos = base::ClampedNumeric<short>(_VisibleStartIndex()) + viewportPos.Y;
COORD bufferPos = { viewportPos.X, yPos };
const auto yPos = _VisibleStartIndex() + viewportPos.Y;
til::point bufferPos = { viewportPos.X, yPos };
_activeBuffer().GetSize().Clamp(bufferPos);
return bufferPos;
}
@@ -532,7 +579,7 @@ COORD Terminal::_ConvertToBufferCell(const COORD viewportPos) const
// - coordSelectionStart - Not used
// - coordSelectionEnd - Not used
// - attr - Not used.
void Terminal::ColorSelection(const COORD, const COORD, const TextAttribute)
void Terminal::ColorSelection(const til::point, const til::point, const TextAttribute)
{
THROW_HR(E_NOTIMPL);
}

View File

@@ -14,13 +14,12 @@ Viewport Terminal::GetViewport() noexcept
return _GetVisibleViewport();
}
COORD Terminal::GetTextBufferEndPosition() const noexcept
til::point Terminal::GetTextBufferEndPosition() const noexcept
{
// We use the end line of mutableViewport as the end
// of the text buffer, it always moves with the written
// text
COORD endPosition{ _GetMutableViewport().Width() - 1, gsl::narrow<short>(ViewEndIndex()) };
return endPosition;
return { _GetMutableViewport().Width() - 1, ViewEndIndex() };
}
const TextBuffer& Terminal::GetTextBuffer() const noexcept
@@ -38,7 +37,7 @@ void Terminal::SetFontInfo(const FontInfo& fontInfo)
_fontInfo = fontInfo;
}
COORD Terminal::GetCursorPosition() const noexcept
til::point Terminal::GetCursorPosition() const noexcept
{
const auto& cursor = _activeBuffer().GetCursor();
return cursor.GetPosition();
@@ -104,10 +103,10 @@ const std::wstring Microsoft::Terminal::Core::Terminal::GetHyperlinkCustomId(uin
// - The location
// Return value:
// - The pattern IDs of the location
const std::vector<size_t> Terminal::GetPatternId(const COORD location) const noexcept
const std::vector<size_t> Terminal::GetPatternId(const til::point location) const noexcept
{
// Look through our interval tree for this location
const auto intervals = _patternIntervalTree.findOverlapping(til::point{ location.X + 1, location.Y }, til::point{ location });
const auto intervals = _patternIntervalTree.findOverlapping({ location.X + 1, location.Y }, location);
if (intervals.size() == 0)
{
return {};
@@ -147,7 +146,7 @@ catch (...)
return {};
}
void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd)
void Terminal::SelectNewRegion(const til::point coordStart, const til::point coordEnd)
{
#pragma warning(push)
#pragma warning(disable : 26496) // cpp core checks wants these const, but they're decremented below.
@@ -178,8 +177,8 @@ void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd)
_NotifyScrollEvent();
}
realCoordStart.Y -= gsl::narrow<short>(_VisibleStartIndex());
realCoordEnd.Y -= gsl::narrow<short>(_VisibleStartIndex());
realCoordStart.Y -= _VisibleStartIndex();
realCoordEnd.Y -= _VisibleStartIndex();
SetSelectionAnchor(realCoordStart);
SetSelectionEnd(realCoordEnd, SelectionExpansion::Char);

View File

@@ -36,22 +36,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
static constexpr std::wstring_view SelectionBackgroundColorTag{ L"SelectionBackground" };
static const std::array<hstring, 16> TableColorNames = {
RS_(L"ColorScheme_Black/Text"),
RS_(L"ColorScheme_Red/Text"),
RS_(L"ColorScheme_Green/Text"),
RS_(L"ColorScheme_Yellow/Text"),
RS_(L"ColorScheme_Blue/Text"),
RS_(L"ColorScheme_Purple/Text"),
RS_(L"ColorScheme_Cyan/Text"),
RS_(L"ColorScheme_White/Text"),
RS_(L"ColorScheme_BrightBlack/Text"),
RS_(L"ColorScheme_BrightRed/Text"),
RS_(L"ColorScheme_BrightGreen/Text"),
RS_(L"ColorScheme_BrightYellow/Text"),
RS_(L"ColorScheme_BrightBlue/Text"),
RS_(L"ColorScheme_BrightPurple/Text"),
RS_(L"ColorScheme_BrightCyan/Text"),
RS_(L"ColorScheme_BrightWhite/Text")
RS_(L"ColorScheme_Black/Header"),
RS_(L"ColorScheme_Red/Header"),
RS_(L"ColorScheme_Green/Header"),
RS_(L"ColorScheme_Yellow/Header"),
RS_(L"ColorScheme_Blue/Header"),
RS_(L"ColorScheme_Purple/Header"),
RS_(L"ColorScheme_Cyan/Header"),
RS_(L"ColorScheme_White/Header"),
RS_(L"ColorScheme_BrightBlack/Header"),
RS_(L"ColorScheme_BrightRed/Header"),
RS_(L"ColorScheme_BrightGreen/Header"),
RS_(L"ColorScheme_BrightYellow/Header"),
RS_(L"ColorScheme_BrightBlue/Header"),
RS_(L"ColorScheme_BrightPurple/Header"),
RS_(L"ColorScheme_BrightCyan/Header"),
RS_(L"ColorScheme_BrightWhite/Header")
};
static const std::array<std::wstring, 9> InBoxSchemes = {
@@ -187,7 +187,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (std::find(std::begin(InBoxSchemes), std::end(InBoxSchemes), schemeName) != std::end(InBoxSchemes))
{
// load disclaimer for in-box profiles
disclaimer = RS_(L"ColorScheme_DeleteButtonDisclaimerInBox/Text");
disclaimer = RS_(L"ColorScheme_DeleteButtonDisclaimerInBox");
}
DeleteButtonDisclaimer().Text(disclaimer);

View File

@@ -93,7 +93,7 @@
<Grid.RowDefinitions>
<!-- profile name -->
<RowDefinition Height="*" />
<RowDefinition Height="20" />
<!-- author and version -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
@@ -109,20 +109,25 @@
<TextBlock Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
Height="20"
AutomationProperties.AccessibilityView="Raw"
Text="{x:Bind Name}" />
<TextBlock Grid.Row="1"
Grid.Column="1"
Height="20"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Author}" />
Text="{x:Bind Author}"
Visibility="{x:Bind local:Converters.StringNotEmptyToVisibility(Author)}" />
<TextBlock Grid.Row="1"
Grid.Column="2"
Height="20"
AutomationProperties.AccessibilityView="Raw"
Style="{ThemeResource SecondaryTextBlockStyle}"
Text="{x:Bind Version}" />
Text="{x:Bind Version}"
Visibility="{x:Bind local:Converters.StringNotEmptyToVisibility(Version)}" />
</Grid>
</DataTemplate>

View File

@@ -179,7 +179,7 @@
</Frame>
<!-- Explicitly set the background color on grid to prevent the navigation animation from overflowing it -->
<Grid Grid.Row="1"
Height="80"
Height="55"
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
BorderThickness="0,1,0,0">
<Grid.ColumnDefinitions>
@@ -196,14 +196,14 @@
HorizontalAlignment="Right"
VerticalAlignment="Center"
Orientation="Horizontal">
<Button x:Name="ResetButton"
x:Uid="Settings_ResetSettingsButton"
Click="ResetButton_Click" />
<Button x:Name="SaveButton"
x:Uid="Settings_SaveSettingsButton"
Margin="10,0,0,0"
Click="SaveButton_Click"
Style="{StaticResource AccentButtonStyle}" />
<Button x:Name="ResetButton"
x:Uid="Settings_ResetSettingsButton"
Margin="10,0,0,0"
Click="ResetButton_Click" />
</StackPanel>
</Grid>
</Grid>

View File

@@ -34,7 +34,6 @@
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalMUX>true</TerminalMUX>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
@@ -354,5 +353,12 @@
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project>

View File

@@ -8,11 +8,10 @@
using namespace ::winrt::Microsoft::Terminal::TerminalConnection;
using namespace ::winrt::Windows::Foundation;
static constexpr std::wstring_view PreviewText{ L"Windows Terminal\r\nCopyright (c) Microsoft Corporation\r\n\nC:\\Windows\\Terminal> " };
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
PreviewConnection::PreviewConnection() noexcept
PreviewConnection::PreviewConnection(const winrt::hstring previewString) noexcept :
_previewString{ previewString }
{
}
@@ -21,7 +20,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// First send a sequence to disable cursor blinking
_TerminalOutputHandlers(L"\x1b[?12l");
// Send the preview text
_TerminalOutputHandlers(PreviewText);
_TerminalOutputHandlers(_previewString);
}
void PreviewConnection::Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) noexcept

View File

@@ -19,7 +19,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
class PreviewConnection : public winrt::implements<PreviewConnection, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection>
{
public:
PreviewConnection() noexcept;
PreviewConnection(const winrt::hstring previewString) noexcept;
void Initialize(const Windows::Foundation::Collections::ValueSet& settings) noexcept;
void Start() noexcept;
@@ -31,5 +31,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
WINRT_CALLBACK(TerminalOutput, winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler);
TYPED_EVENT(StateChanged, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, IInspectable);
private:
const winrt::hstring _previewString;
};
}

View File

@@ -14,10 +14,12 @@
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Navigation;
static const winrt::hstring PreviewText{ L"Windows Terminal\r\nCopyright (c) Microsoft Corporation\r\n\nC:\\Windows\\Terminal> " };
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Profiles_Appearance::Profiles_Appearance() :
_previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make<PreviewConnection>()) }
_previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make<PreviewConnection>(PreviewText)) }
{
InitializeComponent();

View File

@@ -139,43 +139,43 @@
<value>Background</value>
<comment>This is the header for a control that lets the user select the background color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_Black.Text" xml:space="preserve">
<data name="ColorScheme_Black.Header" xml:space="preserve">
<value>Black</value>
<comment>This is the header for a control that lets the user select the black color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_Blue.Text" xml:space="preserve">
<data name="ColorScheme_Blue.Header" xml:space="preserve">
<value>Blue</value>
<comment>This is the header for a control that lets the user select the blue color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_BrightBlack.Text" xml:space="preserve">
<data name="ColorScheme_BrightBlack.Header" xml:space="preserve">
<value>Bright black</value>
<comment>This is the header for a control that lets the user select the bright black color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_BrightBlue.Text" xml:space="preserve">
<data name="ColorScheme_BrightBlue.Header" xml:space="preserve">
<value>Bright blue</value>
<comment>This is the header for a control that lets the user select the bright blue color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_BrightCyan.Text" xml:space="preserve">
<data name="ColorScheme_BrightCyan.Header" xml:space="preserve">
<value>Bright cyan</value>
<comment>This is the header for a control that lets the user select the bright cyan color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_BrightGreen.Text" xml:space="preserve">
<data name="ColorScheme_BrightGreen.Header" xml:space="preserve">
<value>Bright green</value>
<comment>This is the header for a control that lets the user select the bright green color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_BrightPurple.Text" xml:space="preserve">
<data name="ColorScheme_BrightPurple.Header" xml:space="preserve">
<value>Bright purple</value>
<comment>This is the header for a control that lets the user select the bright purple color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_BrightRed.Text" xml:space="preserve">
<data name="ColorScheme_BrightRed.Header" xml:space="preserve">
<value>Bright red</value>
<comment>This is the header for a control that lets the user select the bright red color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_BrightWhite.Text" xml:space="preserve">
<data name="ColorScheme_BrightWhite.Header" xml:space="preserve">
<value>Bright white</value>
<comment>This is the header for a control that lets the user select the bright white color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_BrightYellow.Text" xml:space="preserve">
<data name="ColorScheme_BrightYellow.Header" xml:space="preserve">
<value>Bright yellow</value>
<comment>This is the header for a control that lets the user select the bright yellow color for text displayed on the screen.</comment>
</data>
@@ -183,7 +183,7 @@
<value>Cursor color</value>
<comment>This is the header for a control that lets the user select the text cursor's color displayed on the screen.</comment>
</data>
<data name="ColorScheme_Cyan.Text" xml:space="preserve">
<data name="ColorScheme_Cyan.Header" xml:space="preserve">
<value>Cyan</value>
<comment>This is the header for a control that lets the user select the cyan color for text displayed on the screen.</comment>
</data>
@@ -191,11 +191,11 @@
<value>Foreground</value>
<comment>This is the header for a control that lets the user select the foreground color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_Green.Text" xml:space="preserve">
<data name="ColorScheme_Green.Header" xml:space="preserve">
<value>Green</value>
<comment>This is the header for a control that lets the user select the green color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_Purple.Text" xml:space="preserve">
<data name="ColorScheme_Purple.Header" xml:space="preserve">
<value>Purple</value>
<comment>This is the header for a control that lets the user select the purple color for text displayed on the screen.</comment>
</data>
@@ -203,15 +203,15 @@
<value>Selection background</value>
<comment>This is the header for a control that lets the user select the background color for selected text displayed on the screen.</comment>
</data>
<data name="ColorScheme_Red.Text" xml:space="preserve">
<data name="ColorScheme_Red.Header" xml:space="preserve">
<value>Red</value>
<comment>This is the header for a control that lets the user select the red color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_White.Text" xml:space="preserve">
<data name="ColorScheme_White.Header" xml:space="preserve">
<value>White</value>
<comment>This is the header for a control that lets the user select the white color for text displayed on the screen.</comment>
</data>
<data name="ColorScheme_Yellow.Text" xml:space="preserve">
<data name="ColorScheme_Yellow.Header" xml:space="preserve">
<value>Yellow</value>
<comment>This is the header for a control that lets the user select the yellow color for text displayed on the screen.</comment>
</data>
@@ -1194,7 +1194,7 @@
<value>Rename</value>
<comment>Text label for a button that can be used to begin the renaming process.</comment>
</data>
<data name="ColorScheme_DeleteButtonDisclaimerInBox.Text" xml:space="preserve">
<data name="ColorScheme_DeleteButtonDisclaimerInBox" xml:space="preserve">
<value>This color scheme cannot be deleted or renamed because it is included by default.</value>
<comment>Disclaimer presented next to the delete button when it is disabled.</comment>
</data>

View File

@@ -39,6 +39,10 @@ static constexpr std::string_view ScrollUpKey{ "scrollUp" };
static constexpr std::string_view ScrollUpPageKey{ "scrollUpPage" };
static constexpr std::string_view ScrollToTopKey{ "scrollToTop" };
static constexpr std::string_view ScrollToBottomKey{ "scrollToBottom" };
static constexpr std::string_view ScrollToMarkKey{ "scrollToMark" };
static constexpr std::string_view AddMarkKey{ "addMark" };
static constexpr std::string_view ClearMarkKey{ "clearMark" };
static constexpr std::string_view ClearAllMarksKey{ "clearAllMarks" };
static constexpr std::string_view SendInputKey{ "sendInput" };
static constexpr std::string_view SetColorSchemeKey{ "setColorScheme" };
static constexpr std::string_view SetTabColorKey{ "setTabColor" };
@@ -76,6 +80,8 @@ static constexpr std::string_view QuitKey{ "quit" };
static constexpr std::string_view AdjustOpacityKey{ "adjustOpacity" };
static constexpr std::string_view RestoreLastClosedKey{ "restoreLastClosed" };
static constexpr std::string_view SelectAllKey{ "selectAll" };
static constexpr std::string_view MarkModeKey{ "markMode" };
static constexpr std::string_view ToggleBlockSelectionKey{ "toggleBlockSelection" };
static constexpr std::string_view ActionKey{ "action" };
@@ -352,6 +358,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ ShortcutAction::ScrollUpPage, RS_(L"ScrollUpPageCommandKey") },
{ ShortcutAction::ScrollToTop, RS_(L"ScrollToTopCommandKey") },
{ ShortcutAction::ScrollToBottom, RS_(L"ScrollToBottomCommandKey") },
{ ShortcutAction::ScrollToMark, RS_(L"ScrollToPreviousMarkCommandKey") },
{ ShortcutAction::AddMark, RS_(L"AddMarkCommandKey") },
{ ShortcutAction::ClearMark, RS_(L"ClearMarkCommandKey") },
{ ShortcutAction::ClearAllMarks, RS_(L"ClearAllMarksCommandKey") },
{ ShortcutAction::SendInput, L"" },
{ ShortcutAction::SetColorScheme, L"" },
{ ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") },
@@ -388,6 +398,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{ ShortcutAction::AdjustOpacity, L"" }, // Intentionally omitted, must be generated by GenerateName
{ ShortcutAction::RestoreLastClosed, RS_(L"RestoreLastClosedCommandKey") },
{ ShortcutAction::SelectAll, RS_(L"SelectAllCommandKey") },
{ ShortcutAction::MarkMode, RS_(L"MarkModeCommandKey") },
{ ShortcutAction::ToggleBlockSelection, RS_(L"ToggleBlockSelectionCommandKey") },
};
}();

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