Compare commits

..

190 Commits

Author SHA1 Message Date
Dustin L. Howett
0e301b010d Migrate spelling-0.0.21 changes from main 2022-07-15 14:28:10 -05:00
Mike Griese
27887603b4 tab drag/drop is actually kinda just... done 2022-07-15 14:28:10 -05:00
Mike Griese
87c840b381 Merge branch 'dev/migrie/oop/2/wandavision' into dev/migrie/oop/2/loki 2022-07-15 12:34:34 -05:00
Mike Griese
91616885db Actually, movePane is a lot harder, and I honestly think we can punt that 2022-07-15 12:33:23 -05:00
Mike Griese
089c015347 more notes to go with the parent commit 2022-07-15 11:57:45 -05:00
Mike Griese
dea94d51ad this and 83649075a should probably go to the parent branch 2022-07-15 11:49:16 -05:00
Mike Griese
83649075a7 the final_release thing Dustin was talking about. I think I still need to synchronously close the connection though 2022-07-15 11:11:31 -05:00
Mike Griese
e9375d67f1 Remove the tab from the previous window, as well.
When we move a tab to a new window, we'll hang on to a reference to all the
  content procs, and then remove the whole tab from the UI tree. We'll hang on
  to those refs until the new tab gets attached, and the controls take the next
  ContentProcess reference.
2022-07-15 10:35:02 -05:00
Mike Griese
4b4e057a75 one shot one opportunity 2022-07-15 06:20:19 -05:00
Mike Griese
35c82d37f0 this is important for moving, yknow, the panes 2022-07-14 16:47:29 -05:00
Mike Griese
4acbffb0e3 can I get a whoop whoop 2022-07-14 16:40:39 -05:00
Mike Griese
aaefdf4408 Add comments 2022-07-14 15:44:42 -05:00
Mike Griese
1f2bb760eb Pane officially opened via the serialized actions, via across the process boundary 2022-07-14 15:38:37 -05:00
Mike Griese
5cb4ab1a9e notes 2022-07-14 13:05:04 -05:00
Mike Griese
cfe879da96 Serialize the pane to a Content string, instead of just the guid.
There's a lot of renaming, signature changes here. But StartupActions is a good mechanism for passing panes around, more or less.
2022-07-14 13:01:00 -05:00
Mike Griese
ac62de78a2 IT ABSOLUTELY WORKED 2022-07-13 15:49:04 -05:00
Mike Griese
9870eb1d39 Holy shit all the plumbing worked on the first try 2022-07-13 15:11:26 -05:00
Mike Griese
e06ce39811 more cleanup 2022-07-13 13:08:56 -05:00
Mike Griese
997212f9c5 cleanup 2022-07-13 13:03:40 -05:00
Mike Griese
2ab0a50a11 thank god that horror is cleaned up 2022-07-13 12:40:52 -05:00
Mike Griese
376939cef8 Now panes run out of proc too 2022-07-13 12:25:33 -05:00
Mike Griese
15a7d49f4d Start using PreparedContent everywhere ; add _asyncSplitPane* methods
There were entirely too many places initializing a ControlSettings and Profile with evaluateSettings it and that was a chore. A PreparedContent is a handly little bundle of that, with the IAsyncOperation for starting the content.

We need that to pass to the pane operations, which aren't yet hooked up
2022-07-13 11:53:37 -05:00
Mike Griese
ef595b497a Convert duplicateTab to be out-of-proc 2022-07-13 09:38:12 -05:00
Mike Griese
97676cedd8 Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/endgame 2022-07-13 06:28:55 -05:00
Mike Griese
91bf709ca6 Fix a bad null deref (#13493)
Yep this is my bad. I was trying to fix a bug where only having one of `background` or `unfocusedBackground` would cause the other to never get set to the default. In attempting to force all the logic into an if statement, I messed up the order of operations. My bad 😢 

Regressed in #13456
2022-07-12 19:53:57 +00:00
Carlos Zamora
7abed9f6fb Add keyboard navigation to hyperlinks (#13405)
## Summary of the Pull Request
Adds support to navigate to clickable hyperlinks using only the keyboard. When in mark mode, the user can press [shift+]tab to go the previous/next hyperlink in the text buffer. Once a hyperlink is selected, the user can press <kbd>Ctrl+Enter</kbd> to open the hyperlink.

## References
#4993 

## PR Checklist
* [x] Closes #6649
* [x] Documentation updated at https://github.com/MicrosoftDocs/terminal/pull/558

## Detailed Description of the Pull Request / Additional comments
- Main change
   - The `OpenHyperlink` event needs to be piped down to `ControlCore` now so that we can open a hyperlink at that layer.
   - `SelectHyperlink(dir)` searches the buffer in a given direction and finds the first hyperlink, then selects it.
   - "finding the hyperlink" is the tough part because the pattern tree takes in buffer coordinates, searches through the buffer in that given space, then stores everything relative to the defined space. Normally, the given buffer coordinates would align with the viewport's start and end. However, we're now trying to search outside of the viewport (sometimes), so we need to manage two coordinate systems at the same time.
   - `convertToSearchArea()` lambda was used to convert a given coordinate into the search area coordinate system. So if the search area is the visible viewport, we spit out a viewport position. If the search area is the _next_ viewport, we spit out a position relative to that.
   - `extractResultFromList()` lambda takes the list of patterns from the pattern tree and spits out the hyperlink we want. If we're searching forwards, we get the next one. Otherwise, we get the previous one. We explicitly ignore the one we're already on. If we don't find any, we return `nullopt`.
   - Now that we have all these cool tools, we use them to progressively search through the buffer to find the next/previous hyperlink. Start by searching the visible viewport _after_ (or _before_) the current selection. If we can't find anything, go to the next "page" (viewport scrolled up/down). Repeat this process until something comes up.
   - If we can't find anything, nothing happens. We don't wrap around.
- Other relevant changes
   - the `copy` action is no longer bound to `Enter`. Instead, we manually handle it in `ControlCore.cpp`. This also lets us handle <kbd>Shift+Enter</kbd> appropriately without having to take another key binding.
   - `_ScrollToPoint` was added. It's a simple function that just scrolls the viewport such that the provided buffer position is in view. This was used to de-duplicate code.
   - `_ScrollToPoint` was added into the `ToggleMarkMode()` function. Turns out, we don't scroll to the new selection when we enter mark mode (whoops!). We _should_ do that and we should backport this part of the change too. I'll handle that.
   - add some clarity when some functions are using the viewport position vs the buffer position. This is important because the pattern interval tree works in the viewport space.

## Validation Steps Performed
- case: all hyperlinks are in the view
   -  get next link
   -  get prev link
-  case: need to scroll down for next link
-  case: need to scroll up for next link
2022-07-12 19:51:37 +00:00
Mike Griese
b4a52c847f Send focus events even in ReadOnly mode (#13483)
Does what it says on the tin. When we get focused, temporarily turn off readonly mode, as to not pop the dialog when the focus sequence is eventually sent to the connection. 

* closes #13461
2022-07-12 19:48:34 +00:00
Mike Griese
3f21996589 A pile of Theming nits fixes (#13465)
The main fix here is for the caption button colors. If you had a dark OS/app theme, and a light titlebar, we'd end up with light glyphs, so the caption buttons would be impossible to find.

There's also a pile of nits from #12992 in here. Probably enough to close #13456 out, but I'll let Dustin be the judge. 

Filing today, to get in for 1.16 selfhost (@DHowett)
2022-07-12 12:30:21 +00:00
Leonard Hecker
fd74d59c6c Extend test coverage of TestDbcsWriteRead (#13316)
`TestDbcsWriteRead` failed to properly test all text input scenarios.
In order to write wide characters with `CHAR_INFO` structs using the `W` APIs
one must still repeat the `CHAR_INFO` twice, once with `COMMON_LVB_LEADING_BYTE`
and once with `COMMON_LVB_TRAILING_BYTE` set in the attributes. This is because
`CHAR_INFO` APIs are column oriented. `TestDbcsWriteRead` on the other hand
only tested the scenario of sending wide characters without those flags.

This commit fixes the problem by introducing a `UnicodeDoubled` mode and
increases the number of test patterns from 14 to 17. Due to the existing
code having been written with the false assumption in mind, a simpler
modification resulted in +1100 LOC. As such I opted to rewrite the code instead
and replaced the potentially buggy output generators with static arrays.

Code page 437 tests were removed, as it contains no DBCS characters anyways.

This is preliminary work for #8000.
2022-07-11 22:03:01 +00:00
James Holderness
04478d1df0 Add line breaks in the debug tap output (#13475)
## Summary of the Pull Request

When the debug tap converts control characters into visible glyphs, it
ends up losing the structure of the output, and that can sometimes make
things difficult to read. This PR attempts to alleviate that problem by
reinjecting an actual line break in the debug stream whenever an `LF`
control is received.

## PR Checklist
* [x] Closes #12312
* [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: #12312

## Validation Steps Performed

I've tested the updated debug tab with a number of different shells, and
also a couple of different apps. When there aren't many linefeeds in the
output, it's obviously not going to make much of a difference, but when
there are, I think it definitely improves the readability.
2022-07-11 19:09:38 +00:00
Davide Giacometti
589286a357 Don't set full screen to quake window (#13473)
If launch mode is set to full screen quake window is opened in full
screen.

## Validation Steps Performed
- Set startup > launch mode > full screen
- Launch quake window
- Quake window shouldn't be opened in full screen

Closes #12894
2022-07-11 18:49:01 +00:00
Leonard Hecker
d74b66a0a7 AtlasEngine: Improve glyph generation performance (#13477)
#13458 added the ability to reuse tiles from our glyph atlas texture
so that we stop running out of GPU memory for complex Unicode.
This however can result in our glyph generation being a performance issue in
edge cases, to the point that the application may feel outright unuseable.

CJK glyphs for instance can easily exceed the maximum atlas texture size
(twice the window size), but take a significant amount of CPU and GPU time to
rasterize and draw, which results in "jelly scrolling" down to ~1 FPS.
This PR improves the situation of the latter half by directly drawing
glyphs into the texture atlas without an intermediate scratchpad texture.

This reduces GPU usage by 96% on my system (33% -> 2%) which improves general
render performance by ~100% (15 -> 30 FPS). CPU usage remains the same however,
but that's not really something we can do anything about at this time.
The atlas texture is already our primary means to reduce the CPU cost after all.

## Validation Steps Performed
* Disable V-Sync for OpenConsole in NVIDIA Control Panel
* Enable `debugGlyphGenerationPerformance`
* Print the entire CJK block U+4E00..U+9FFF
* Measure the above GPU usage and FPS improvements 
  (Alternatively: Just scroll around and judge the "jellyness".)
2022-07-11 18:31:21 +00:00
Mike Griese
ae5b04f7b2 Merge branch 'dev/migrie/oop/2/infinity-war' into dev/migrie/oop/2/endgame 2022-07-11 13:01:04 -05:00
Mike Griese
3434208947 Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/infinity-war 2022-07-11 13:00:38 -05:00
Mike Griese
32379c29f0 Wrap the tooltips on the new tab button (#13463)
In non-en-us locales, these tooltips can get really long and get clipped.

Closes MSFT:39603031
See Also #9913
2022-07-11 17:13:55 +00:00
James Holderness
cd2166aedf Allow leading spaces to bypass console aliases (#13476)
## Summary of the Pull Request

When you create a console alias that overrides an existing command, it
should still be possible to execute the original command by prefixing it
with a space. However, at some point in the past, there was an attempt
to improve the usability by trimming leading spaces, and that ended up
breaking this functionality. This PR reverts that change, so leading
spaces can once again be used to bypass an alias.

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

## Validation Steps Performed

I've updated the existing alias unit test for leading spaces to match
the new behavior, i.e. it now confirms that a command with leading
spaces will not match the alias.

I've also manually confirmed that the `doskey` test case reported in
issue #4189 is now working as expected.
2022-07-11 12:36:08 +00:00
Leonard Hecker
66f4f9d9ea AtlasEngine: Implement LRU invalidation for glyph tiles (#13458)
So far AtlasEngine would only grow the backing texture atlas once it gets full,
without the ability to reuse tiles once it gets full. This commit adds LRU
capabilities to the glyph-to-tile hashmap, allowing us to reuse the least
recently used tiles for new ones once the atlas texture is full.
This commit uses a quadratic growth factor with power-of-2 textures,
resulting in a backing atlas of 1x to 2x the size of the window.
While AtlasEngine is still incapable of shrinking the texture, it'll now at
least not grow to 128MB or result in weird glitches under most circumstances.

## Validation Steps Performed
* Print `utf8_sequence_0-0x2ffff_assigned_printable_unseparated.txt`
  from https://github.com/bits/UTF-8-Unicode-Test-Documents
* Scroll back up to the top
* PowerShell input line is still there rendering as ASCII. 
2022-07-11 12:23:48 +00:00
PankajBhojwani
bbc570d107 Implement MVVM for the Rendering page (#13391)
## Summary of the Pull Request
Implements a `RenderingViewModel` for the Rendering page in the SUI

## PR Checklist
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Validation Steps Performed
Rendering page still works
2022-07-08 22:50:38 +00:00
PankajBhojwani
238b5c2e22 Implement MVVM for the Interaction page (#13378)
## Summary of the Pull Request
Implements an `InteractionViewModel` for the Interaction page in the SUI

## PR Checklist
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Validation Steps Performed
Interaction page still works
2022-07-08 22:13:15 +00:00
Sergey
55dd4af9cb Add ability to select where new tab will appear (#13421)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
Adds ability to select where new tab will appear: at the end or after currently selected tab.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #12955 
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
PR adds setting "NewTabPosition" in global appearances with dropdown list and uses it then creating new tabs. This setting does not affect settings tab position (should it?).
There should also be a documentation update, I'm just waiting to see if this change even acceptable.
<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2022-07-08 21:46:01 +00:00
PankajBhojwani
2970017243 Implement MVVM for the GlobalAppearance page (#13390)
## Summary of the Pull Request
Implements a `GlobalAppearanceViewModel` for the GlobalAppearance page in the SUI

## PR Checklist
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Validation Steps Performed
Global appearance page still works
2022-07-08 20:49:03 +00:00
PankajBhojwani
1faf67fba3 Implement MVVM for the Launch page (#13377)
## Summary of the Pull Request
Implements a `LaunchViewModel` for the Launch page in the SUI

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

## Validation Steps Performed
Launch page still works
2022-07-08 11:55:37 +00:00
Mike Griese
024b9fc0f4 Add a setting for the unfocused tabRow background color (#13049)
Adds `tabRow.unfocusedBackground` to the theme properties.

When provided, the window will use this ThemeColor as the color of the tab row when the window is inactive. 

When omitted, the window will fall back to the default tab row color, `{"key": "TabViewBackground"}` from our App.xaml.

* [ ] tests added.
* [x] Closes #4862
* [ ] Needs a whole pile of docs updates, which we'll do at the end here.


This actually helped validate #12992 quite a bit. I found a bunch of bugs concerning null colors, null objects. Json parsing is hard 😛
2022-07-07 17:57:48 +00:00
Mike Griese
aa4e9f5414 Also hide the scroll marks when hiding the scrollbar (#13454)
This one's pretty obvious. I added another scrollbar sized grid to the terminal,
but I forgot to collapse it when the user requests `"scrollbarState": "hidden"`.

* [x] Closes #13446
* [x] I work here
2022-07-07 17:30:50 +00:00
Mike Griese
76b00e3b31 Add support for tab.background to themes (#13178)
## Summary of the Pull Request

Adds support for the `tab.background` property to themes. This is also a ThemeColor, so it accepts, colors, `accent`, and `terminalBackground`, just like everything else.

## References
* See #3327 
* ⚠️ targets #12992 ⚠️


## PR Checklist
* [x] Closes #702
* [x] I work here
* [ ] Tests added/passed
* [n/a] Requires documentation to be updated - YUP

## Detailed Description of the Pull Request / Additional comments

I apparently left behing an optional color in TerminalTab for theme colors some time ago, just never used it. Crazy, huh?

## Validation Steps Performed

gifs below
2022-07-07 08:26:17 -05:00
Mike Griese
07d58a800c Initial Theme support (#12992)
##### ⚠️ targeting 1.15

## Summary of the Pull Request

Adds support for Themes, a new type of customization for the Terminal. Themes allow the user to customize elements of the Terminal window itself. In this first iteration, this PR adds support for two main properties:
* enabling Mica as the window backdrop
* changing the tab row color (read: changing the titelbar color)

These represent the most important asks of theming in the Terminal. The properties added in this PR are:

* Theme color variants:
    - `"#rrggbb"` or `"#aarrggbb"`
    - `"accent"`
    - `"terminalBackground"`
* Properties (_listed here in dot notation, but implemented as sub-objects_)
    - `tabRow.background`: accepts a ThemeColor (above)
    - `window.applicationTheme`: accepts one of `{"system", "light", "dark"}`
    - `window.useMica`: accepts a boolean, defaults to false.

## References
* As first described in #3327
* spec'd in #12530

## PR Checklist
* [x] Sorta enables #10509, but doesn't close it. That'll need more comprehensive changes to the titlebar code.
  * **update**: I totally disabled mica, but left the serialization code. It just seems silly without #10509. 
* [x] Closes #1963
* [x] Closes #3774 
* [x] Closes #12939
* [x] Does the bulk of the #3327 work, but I'm going to leave that open since that's become my megathread for everything related to theming.
* [x] I work here
* [x] Tests added/passed
* [ ] Requires documentation to be updated - **SURE DOES**

## Detailed Description of the Pull Request / Additional comments

### --> GO READ #12530 <--

Seriously. 

These themes aren't customizable in the SUI currently. You can change the active theme, and the UI will show all of the defined themes, but they're not editable there. 

They don't layer. You'll need to define your own themes.

Thay can't come from fragments. This is a really cool future idea, but not implemented in this v0.

The sub objects have some gnarly macros to generate a lot of the serialization code for you. 

### TODOs

* [x] I still have yet to establish what the accent color algorithm is. This might be proprietary and require a ThemeHelpers workaround.
* [x] Make sure `terminalBackground` & the SUI result in something sensible
* [x] Make sure runtime BG changes work with `terminalBackground`. One time, they didn't. `printf "\x1b]11;rgb:ff/00/ff\x07"`
* [x] Acrylic Terminal BG's look weird, like, the opacity is always 50% or something. And the tab row looks all wrong then.

## Validation Steps Performed

This is the blob I've been testing with:
<details>

```jsonc
    // "useAcrylicInTabRow": true,
    "theme": "my dark",
    // "theme": "Edge",
    "theme": "orangey",
    "theme": "WHITE",
    // "theme": "terminal",
    "themes": [
        {
            "name": "my dark",
            "window": {
                "applicationTheme": "dark",
                "useMica": true,
            },
            "tabRow": {
                "background": "#00000000",
            },
        },
        {
            "name": "Edge",
            "tabRow": { "background": "accent" },
            "window": { "applicationTheme": "system" }
        },
        {
            "name": "orangey",

            "window": {
                "applicationTheme": "light",
                "useMica": true,
            },
            "tabRow": {
                "background": "#ff8800",
            },
        },
        {
            "name": "WHITE",
            "window": {
                "applicationTheme": "dark",
                "useMica": true,
            },
            "tabRow": {
                "background": "#FFFFFF",
            },
        },
        {
            "name": "terminal",

            "window": {
                "applicationTheme": "dark",
                "useMica": false,
            },
            "tabRow": {
                "background": "terminalBackground",
            },
        },
    ]
```
    
</details>
2022-07-07 06:54:54 -05:00
Mike Griese
f893f7516a Merge branch 'dev/migrie/oop/2/infinity-war' into dev/migrie/oop/2/endgame 2022-07-06 13:14:37 -05:00
Mike Griese
702e15ce5a Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/infinity-war 2022-07-06 13:14:17 -05:00
Mike Griese
ff23726b7c Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/endgame 2022-07-06 07:04:33 -05:00
Mike Griese
7675354b2d notes 2022-07-06 07:04:22 -05:00
Dustin L. Howett
16028dee8b RelEng: Teach ServicingPipeline to infer the version if it's null (#13439)
```
% .\tools\ReleaseEngineering\ServicingPipeline.ps1
Inferred servicing version 1.14
PICK f025c53dba: Remove the fallback to wsl.exe when HKCU\...\Lxss doesn't exist (#13436)
 OK
```
2022-07-06 06:11:53 -05:00
dansmor7
c6b67aad4b Update tab hover colors (#13434)
The hover tab color used to be generated from the selected tab color, which would end up lighter or darker, and white-gray colors would end up pink.
It is now simply the selected tab color with 60% opacity. This is also how brushes are created for accent buttons and color buttons (although with different opacity levels).
2022-07-05 16:56:01 -05:00
Leonard Hecker
bd403dc8e7 Switch to VS17 and C++20 (#13368)
C++20 goodies include:
* 3-way comparison operator `<=>` and `operator==() = default`
* designated initializers
* constraints and concepts
* abbreviated function templates (`void foo(auto bar)`)
* pack-expansions in lambda init-captures
* heterogeneous lookups in `unordered_set` / `unordered_map`
* `consteval` / `constinit`
* `starts_with` / `ends_with` for `string` / `string_view`
* `midpoint`, `lerp`
* `<bit>`
* `<ranges>`
* `<span>`
* `<barrier>`
* `<latch>`
* `<semaphore>`
2022-07-05 21:06:05 +00:00
Dustin L. Howett
f025c53dba Remove the fallback to wsl.exe when HKCU\...\Lxss doesn't exist (#13436)
The main result of this fallback is that we attempt to launch wsl.exe
when the user hasn't installed or interacted with WSL. On our test
machines, that results in the creation of a wsl.exe process that tells
us precisely nothing; on WDAC managed machines it results in an Event
Log entry about spawning another (possibly blocked) process.

The registry is more reliable, and if the "API" it provides changes we
can just rev terminal.

Closes #11716
2022-07-05 20:47:20 +00:00
Carlos Zamora
66ecb0bd63 Update renderer on SwitchSelectionEndpoint (#13435)
## Summary of the Pull Request
In #13370, we should be notifying the renderer that the selection changed. Minor oversight and simple fix.

## References
#4993
#13370 
Closes #13413
2022-07-05 20:38:22 +00:00
Leonard Hecker
95a19624a4 Fix a race condition in CTerminalHandoff::s_StopListening (#13410)
This commit fixes a minor race condition covered as part of #13368.
The member `_pfnHandoff` was read without the mutex `_mtx` being locked first.
The issue was solved by acquiring the lock early and running the entire
`s_StopListening` function with that lock held.
2022-07-05 20:25:14 +00:00
Mike Griese
86dfefa690 Fix the bellsound schema, for real (#13433)
As noted in https://github.com/microsoft/terminal/pull/11511#issuecomment-1173541384.

Missed in #13035
2022-07-05 14:33:00 -05:00
PankajBhojwani
478c2c3613 Update schema with scroll marks actions and settings (#13414)
Update schema with the settings/actions added in #12948 

## PR Checklist
* [x] Closes #13404
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Schema updated.
2022-07-01 14:24:34 -07:00
Dustin Howett
a579566a1d version: bump to 1.16 on main 2022-06-30 23:02:26 -05:00
dependabot[bot]
f1b6b17c58 Bump Newtonsoft.Json from 12.0.3 to 13.0.1 (#13363)
* Bump Newtonsoft.Json from 12.0.3 to 13.0.1 in /dep/nuget

Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 12.0.3 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/12.0.3...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Complete the Newtonsoft.Json upgrade to 13.0.1

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
2022-06-30 22:31:40 -05:00
Carlos Zamora
7b8a53c030 Introduce switchSelectionEndpoint action (#13370)
## Summary of the Pull Request
Introduces the `switchSelectionEndpoint` action which switches whichever selection endpoint is targeted when a selection is present. For example, if you are targeting "start", `switchSelectionEndpoint` makes it so that now you are targeting "end". This also updates the selection markers appropriately.

## References
Spec - #5804 
#13358
Closes #3663

## Detailed Description of the Pull Request / Additional comments
Most of the code is just standard code of adding a new action. Other than that, we have...
- if there is no selection, the action fails and the keybinding is passed through (similar to `copy()`)
- when we update the selection endpoint, we need to also update the "pivot". This ensures that future calls of `UpdateSelection()` respect this swap.
- [Corner Case] if the cursor is being moved, we make it so that you basically "anchored" an endpoint and you don't have to hold shift anymore.
2022-07-01 01:44:39 +00:00
Dustin Howett
d6a9e9ffb6 Merge remote-tracking branch 'openconsole/inbox' 2022-06-30 20:17:07 -05:00
Dustin Howett
eb1d6b599e OS PR 7534836: HOTFIX MSFT-40226902 by leaking the onecore renderers on exit
## Why is this change being made?
Our conhost OneCore backend isn't as thoroughly tested as our Win32 one and fell victim to the general "bugginess" of our shutdown handling centered around `ServiceLocator::RundownAndExit`. In the past we simply leaked all resources, but changed it so that a cleanup on exit occurs, so that we can track resource leaks for instance. This broke OneCore which has a more delicate shutdown than Win32.

## What changed?
This commit reverts changes being made in 9d7a46f64c and after.

## How was the change tested?
This change was tested in a OneCore VM by repeatedly spawning subprocesses and ensuring they exit in a timely manner and without unexpected crashes.

Related work items: MSFT-40226902, MSFT-22128499

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev 0683758a0846aefbbe50730c3cd336623328ddeb
2022-07-01 01:11:47 +00:00
Carlos Zamora
2cd2351deb Miscellaneous bug fixes for Mark Mode (#13358)
## Summary of the Pull Request
1. [copy on select] when manually copying text (i.e. kbd or right-click) while in mark/quick-edit mode, we now dismiss the selection.
2. `Enter` is now bound to copy by default. 
    - This works very well with mark mode and provides a more consistent behavior with conhost's selection experience overall.
    - "why not hardcode `Enter` as a way to copy when in mark mode?"
        - In an effort to make this as configurable as possible, I decided to make it a configurable keybinding, but am open to suggestions.
3. selection markers
   a. we now hide the selection markers when multi-clicking the terminal.
   b. selection markers are now properly shown when a single cell selection exists
      - Prior to this PR, any single cell selection would display both markers. Now, we actually track which endpoint we're moving and display the appropriate one.
4. ensures that when you use keyboard selection to move past the top/bottom of the scroll area, we clamp it to the origin/bottom-right respectively. The fix is also better here in that it provides consistent behavior across all of the `_MoveByX` functions.
5. adds `toggleBlockSelection` to the schema

## References
#13053 

## Validation Steps Performed
Did a whole flowchart of expected behavior with copy on select:
- enable `copyOnSelect`
   - make a selection with the mouse
      -  right-click should copy the text --> clear the selection --> paste
   - use keyboard selection to quick-edit the existing selection
      -  `copy` action should clear the selection
      -  right-click should copy the text --> clear the selection --> paste

Played with selection markers a bit in mark mode and quick edit mode. Markers are updating appropriately.
2022-06-30 20:07:07 -05:00
msftbot[bot]
843e61aa8a Migrate FabricBot Tasks to Config-as-Code (#13397)
FabricBot is now a [config-as-code-only] platform. As a result, while
you can still use the [FabricBot Configuration Portal] to modify your
FabricBot configuration, you can no longer save the changes. The only
way to save changes to your configuration at the moment is to _export
configuration_ from the portal and upload the exported configuration to
`.github/fabricbot.json` in your repository. In this pull request, we
are adding your FabricBot configuration to your repository at
`.github/fabricbot.json` so that you can make changes to it going
forward.

While the [FabricBot Configuration Portal] is the *only way* to modify
your FabricBot configuration at the moment, we have a feature on our
backlog to publish the JSON schema defining the structure of the
FabricBot configuration file. With the JSON schema, you can (1) use a
plaintext editor of your choice to modify the FabricBot configuration
file and use the schema to validate the file after editing or (2)
[configure VS Code] to use the schema when editing FabricBot
configuration file to take advantage of convenience features such as
automatic code completion and field description on mouseover.

[config-as-code-only]: https://eng.ms/docs/products/1es-data-insights/merlinbot/extensions/bot-config-as-code
[FabricBot Configuration Portal]: https://portal.fabricbot.ms/bot/?repo=microsoft/terminal
[configure VS Code]: https://code.visualstudio.com/Docs/languages/json#_json-schemas-and-settings

Co-authored-by: msftbot[bot] <48340428+msftbot[bot]@users.noreply.github.com>
Co-authored-by: Dustin Howett <duhowett@microsoft.com>
2022-06-30 19:59:51 -05:00
Carlos Zamora
f785168aac Remove most uses of CompareInBounds (#13244)
## Summary of the Pull Request
Replaces most uses of `Viewport::CompareInBounds()` with `til::point`'s `<` and `>` operators. `CompareInBounds` has been the cause of a bunch of UIA crashes over the years. Replacing them entirely ensures that the `FAILFAST_IF` isn't ever touched.

Unfortunately, we still need `IncrementInBounds` and `DecrementInBounds` to have support for that exclusive end.

## References
#13183
2022-07-01 00:06:33 +00:00
Leonard Hecker
8fba292bd7 Fix coordSizeUnscaled calculation in AtlasEngine (#13384)
This commit fixes a bug causing the OpenConsole to get increasingly larger
every time the font is changed when the AtlasEngine is active.
The only impact this bug had on Windows Terminal is that the
`font-size` in HTML and RTF selection copies are too large.

## Validation Steps Performed
* OpenConsole window size doesn't change when
  switching between main and alt buffer 
2022-06-30 21:16:19 +00:00
Dustin Howett
9e8427d81e Merge remote-tracking branch 'openconsole/inbox' into main 2022-06-24 17:51:35 -05:00
Dustin Howett
059b53bf94 Migrate OSS up to 8962f88f9 2022-06-24 17:39:59 -05:00
Dustin Howett
4d48f305a1 OS PR 7517171: Fix a race condition in ServiceLocator::RundownAndExit
[Git2Git] Merged PR 7517171: Fix a race condition in ServiceLocator::RundownAndExit

The whole premise of RundownAndExit is that one thread enters it, runs
down the console and terminates it. One thread enters, 0 threads leave.

After some recent console locking changes, we found that on OneCore
devices it was possible for two threads (the I/O thread and the coniosrv
Input thread) to try to rundown and exit at the same time.

This SRWLOCK prevents that from happening.

Fixes #40146639

Related work items: #40146639 Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev ff235c6e49e065bccc937dee91f43ff310b5743c

Related work items: #40146639
2022-06-24 22:20:36 +00:00
Dustin Howett
06e2317012 OS PR 7517072: Force the double-click tests to have a high click timeout
[Git2Git] Merged PR 7517072: conhost: Force the double-click tests to have a high click timeout

The conhost tests might run somewhere that does not have a double click time.
We should hardcode a value for the purposes of testing.

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev 3c2620dab577e16e8672b369e4dfcde7c02881a1

Related work items: MSFT-40150725
2022-06-24 21:52:13 +00:00
Dustin Howett
4071df73ba OS build fixes on top of 24a53d496
This introduces the build rules for midi.lib to the OS!

Retrieved from https://microsoft.visualstudio.com os.2020 OS official/rs_wdx_dxp_windev fb066544f112ae491bb1d1f73578bc47fa167b41
2022-06-24 20:58:03 +00:00
Mike Griese
19605bf75b A tab should be able to be created without a pane, and this works for that 2022-06-23 15:27:01 -05:00
Dustin L. Howett
8962f88f90 Disable the VT color quirk for pwsh and modern inbox powershell (#13352)
In #6810, we introduced a "quirk" for all known versions of PowerShell
that suppressed their requests for black background/gray foreground.
This was done to avoid an [issue in PSReadline] where it would paint
black bars all over the screen if the default background color wasn't
the same as the ANSI black color.

Years have passed since that quirk was introduced. The underlying bug
was fixed, and the fix was released broadly long ago. It's time for us
to remove the quirk... almost.

Terminal still runs on versions of Windows that ship a broken version of
PSReadline. We must maintain the quirk there -- the user can't do
anything about it, and we would make their experience worse if we
removed the quirk entirely.

PowerShell 7.0 also ships a broken version of PSReadline. It is still in
support for another 6 months, but updates have been available for some
time. We can encourage users to update.

Therefore, we only need the quirk for Windows PowerShell, and then only
for specific versions of Windows.

_Inside Windows_, we don't even need that: we're guaranteed to be built
alongside a fixed version of PowerShell!

Closes #6807

[issue in PSReadline]: https://github.com/PowerShell/PSReadLine/issues/830#issuecomment-650508857
2022-06-23 15:40:27 +00:00
Mike Griese
eb4b2a7534 The first tab now opens out-of-proc too
We're gonna definitely run into a lot of pain here. Like, the initialization
  finishes now bbefore the tabs are created, so the "no tabs got opened" check
  needs to be changed.

  I don't think I need both resume_bg's in CreateContent and also in AsyncCreateTab
2022-06-23 09:05:00 -05:00
Carlos Zamora
72a4e936cc Fix moving selection past scroll area (#13318)
## Summary of the Pull Request
Introduced in #10824, this fixes a bug where you could use keyboard selection to move below the scroll area. Instead, we now clamp movement to the mutable viewport (aka the scrollable area). Specifically, we clamp to the corners (i.e. 0,0 or bottom right cell of scroll area).

## Validation Steps Performed
 (no output) try to move past bottom of viewport
 (with output, at bottom of scroll area) try to move past viewport
 (with output, NOT at bottom of scroll area) try to move past viewport
 try to move past top of viewport
2022-06-22 23:16:24 +00:00
Mike Griese
1f083cbd89 differentiate these two, for clarity 2022-06-22 16:45:38 -05:00
Dustin Howett
1ac7fe16ae Migrate OSS up to 24a53d496 2022-06-22 15:35:12 -05:00
Dustin Howett
ff7a632f0f Import OS build fixes on top of 7dbe741e1 2022-06-22 20:29:49 +00:00
Mike Griese
797ebae6e1 guess what, this totally isn't used! 2022-06-22 14:45:44 -05:00
Mike Griese
4f7e99123a Merge branch 'dev/migrie/oop/2/infinity-war' into dev/migrie/oop/2/endgame 2022-06-22 11:20:16 -05:00
Mike Griese
b8cd2b239f that was vestigial anyways 2022-06-22 11:19:24 -05:00
Leonard Hecker
24a53d4968 Dismiss Terminal-by-default banner on handoff (#13344)
It's not useful to notify users that WT can be made the default if it's already
clearly being used for handoff. This commit will suppresses the banner then.

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

## Validation Steps Performed
* Modify `TerminalPage::ShowSetAsDefaultInfoBar` to not check for
  `CascadiaSettings::IsDefaultTerminalSet()`
* Set Terminal Dev as the default
* Set incoming connections to open in the latest Terminal window
* Delete `state.json` after every test below
* Launching Terminal Dev shows the banner 
  Launching `cmd.exe` dismisses the banner in the current Terminal 
* Launching `cmd.exe` launches Terminal Dev without banner 
2022-06-21 23:02:29 +00:00
Mike Griese
023eb75550 this was definitely a bug 2022-06-21 16:52:45 -05:00
Dustin L. Howett
0b97c7b5ca Strip XAML files from the MSIX payload (#13351)
These files are vestigial, because we are also shipping (either as loose
files or embedded in resources.pri) precompiled xbf/xaml binary format
files.

This saves us almost 500kb on disk.

Fixes #11687

Validation
----------
I ran a local build and saw that it produced a working Terminal, packaged
and unpackaged.
2022-06-21 13:37:42 -05:00
Mike Griese
f7d93849a8 this was LOAD BEARING 2022-06-21 13:15:21 -05:00
Mike Griese
7707716b08 Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/infinity-war 2022-06-21 11:44:43 -05:00
Carlos Zamora
6436e712e7 Add selection marker overlays for keyboard selection (#10865)
## Summary of the Pull Request
This introduces a selection marker overlay that tells the user which endpoint is currently being moved by the keyboard. The selection markers are respect font size changes and `cursor` color.

## References
#715 - Keyboard Selection
#2840 - Keyboard Selection Spec
#5804 - Mark Mode Spec

## Detailed Description of the Pull Request / Additional comments
- `TermControl` layer:
   - Use a canvas (similar to the one used for hyperlinks) to be able to draw the selection markers.
   - If we are notified that the selection changed, update the selection markers appropriately.
   - `UpdateSelectionMarkersEventArgs` lets us distinguish between mouse and keyboard selections.  `ClearMarkers` is set to true in the following cases...
      1.  Mouse selection, via SetEndSelectionPoint
      2. `LeftClickOnTerminal`, pretty self-explanatory
      3. a selection created from searching for text
- `ControlCore` layer:
   - Responsible for notifying `TermControl` to update the selection markers when a selection has changed.
   - Transfers info (the selection endpoint positions and which endpoint we're moving) from the terminal core to the term control.
- `TerminalCore` layer:
   - Provides the viewport position of the selection endpoints.


## Validation Steps Performed
- mouse selection (w/ and w/out shift) --> no markers
- keyboard selection --> markers
- markers update appropriately when we pivot the selection
- markers scroll when you hit a boundary
- markers take the color of the cursor color setting
- markers are resized when the font size changes
2022-06-20 17:47:53 -05:00
James Holderness
08c2f350e6 Make sure conpty is flushed before clearing scrollback (#13324)
## Summary of the Pull Request

When you execute a `cls` in the cmd shell, or `Clear-Host` in
PowerShell, we have a pair of shims that attempt to detect those
operations and forward an `ED3` sequence to conpty to clear the
scrollback.

If there was a linefeed at the bottom of the viewport immediately 
prior to those functions being called, that event might still be
pending, and only forwarded to conpty after the `ED3`. The result
then is a line pushed into the scrollback that shouldn't be there.

This PR tries to avoid that situation by forcing the renderer to
flush before the `ED3` sequence is sent.

## References

The `cls` and `Clear-Host` shims were originally added in PR #5627.

## PR Checklist
* [x] Closes #5770
* [x] Closes #13320
* [x] CLA signed.
* [ ] 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

## Validation Steps Performed

I've manually tested in PowerShell with `echo Hello; Clear-Host` (this
is the only way I could reliably reproduce the original problem), and in
the cmd shell with `cls`. Both cases are now working as expected.
2022-06-20 17:47:35 -05:00
Ofek Lev
a5fb91dd4c Fix typos in dev build script (#13333) 2022-06-20 11:38:46 -05:00
Mike Griese
848314ef17 Fix a deadlock in ShowWindow (#13309)
When we send this ShowWindow message, if we send it to it's
going to need to get processed by the window message thread before
returning. We're handling this message under lock. However, the first
thing the conhost message thread does is lock the console. That'll
deadlock us. So unlock here, first, to let the message thread deal with
this message, then re-lock so later on this thread can unlock again
safely.

* [x] Closes #13301 
* [x] Tested conhost
* [x] Tested terminal
2022-06-16 22:10:00 +00:00
Dustin L. Howett
deffbbc7f5 Regenerate CodepointWidthDetector from Unicode 14.0 (#13292) 2022-06-16 21:56:01 +00:00
Mike Griese
f12ee745ef Update the scrollbar postiton on scrollToMark (#13291)
When I moved this into ControlCore, I forgot that UserScrollViewport is usually triggered by the scrollbar updating, so it doesn't ask the UI to update. Since this logic is in ControlCore, it's sorta in a weird place where it needs to communicate both up and down:
* update the `Terminal`'s viewport position
* update the `TermControl`'s scrollbar position

Checklist:

* [x] Closes a bug bash bug
* [x] Missed in #12948 
* See also #11000
2022-06-16 21:55:17 +00:00
Dustin L. Howett
9eb191d545 Fix an issue preventing the compliance pipeline from running (#13289) 2022-06-13 15:48:34 -05: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
Dustin Howett
bfd910c4ca Migrate OSS up to 7dbe741e1 2022-06-07 17:21:20 -05:00
Leonard Hecker
715844b01c 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.

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 

(cherry picked from commit 1b81c6540f)
Service-Card-Id: 82925080
Service-Version: Inbox
2022-06-07 17:00:04 -05: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
Mike Griese
dfd345405a holy nuts it worked
LAWD this is dirty code. But POC, it does work for new tabs from the dropdown. Trick is that MakePane can't be used like that anymore, so gotta find a new way.
2022-05-25 12:36:35 -05:00
Mike Griese
daa2ef139f This is when I realized that asyncmakepane was never going to work 2022-05-24 16:36:40 -05:00
Mike Griese
44ac527f31 more nits, more a11y stuff 2022-05-24 12:09:50 -05: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
52f7664d01 some nits 2022-05-24 10:47:45 -05:00
Mike Griese
223e270778 Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/infinity-war 2022-05-24 10:23:43 -05: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
Mike Griese
eac5cebbc6 Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/infinity-war 2022-05-05 09:21:49 -05:00
Mike Griese
7d4ee45e4e Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/infinity-war 2022-04-28 05:56:45 -05:00
Mike Griese
02fa24cb12 Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/infinity-war 2022-04-20 06:36:40 -05:00
Mike Griese
f898855c82 yes I know this doesn't return that's the whole point 2022-04-20 06:36:31 -05:00
Mike Griese
a38fe5f1a6 woah typos 2022-04-19 16:10:15 -05:00
Mike Griese
bbe32f80e5 Reduce the diff size trivially 2022-04-19 14:37:05 -05:00
Mike Griese
446d07e79f add logging 2022-04-19 12:30:02 -05:00
Mike Griese
a74b45aa2c hey look this assert() doesn't hit anymore 2022-04-19 12:12:45 -05:00
Mike Griese
c588a9c75d cleanup from fixed a11y code 2022-04-19 11:18:11 -05:00
Mike Griese
082c63bde5 this seems to work with narrator. I think this is what I was trying to do 2022-04-18 17:03:39 -05:00
Mike Griese
91977bec5a For this commit, I went with what was in #11501. That seems to have been wrong. I get all sorts of errors. I should to the opposite.
(cherry picked from commit bf0f516634)
2022-04-18 16:17:30 -05:00
Mike Griese
07a1a07e47 When trying to use Narrator, this gets hit and throws an exception. Plumb it through instead 2022-04-18 16:12:01 -05:00
Mike Griese
ce8f8fb618 Make the window smaller because the default is HUUEG 2022-04-18 16:11:09 -05:00
Dustin L. Howett
538285cc45 git2git: remove some more things from the OS build (#12931)
This will result in the deletion of the following directories from the OS tree, under `onecore/windows/core/console/open`:

* doc/
* src/tools/MonarchPeasantPackage/
* src/api-ms-win-core-synch-l1-2-0/
* src/tools/ansi-color/
* src/tools/ColorTool/

We have gotten some PoliCheck flags on `doc/` (thanks to Niksa.md), but also the OS build just doesn't need these folders 😄

(cherry picked from commit 27b63ad02a)
Service-Card-Id: 80783789
Service-Version: Inbox
2022-04-18 14:37:21 -05:00
Mike Griese
b1ee82ae18 Revert "start thinking about moving the timers to being threadpooltimers in the core. I think every x-proc call in TermControl logs that message, so _crap_"
This reverts commit 76d8fa7b7e.
2022-04-18 12:17:33 -05:00
Mike Griese
358edd520a Revert "For this commit, I went with what was in #11501. That seems to have been wrong. I get all sorts of errors. I should to the opposite."
This reverts commit bf0f516634.
2022-04-15 14:05:45 -05:00
Mike Griese
bf0f516634 For this commit, I went with what was in #11501. That seems to have been wrong. I get all sorts of errors. I should to the opposite. 2022-04-15 14:05:38 -05:00
Mike Griese
99308b43e2 This actually works for not loading the resources 2022-04-15 14:04:41 -05:00
Mike Griese
2a9eefc2d9 Merge remote-tracking branch 'origin/main' into dev/migrie/oop/2/infinity-war 2022-04-15 12:02:16 -05:00
Mike Griese
33b1ab9e79 own the handle 2022-04-13 06:47:11 -05:00
Mike Griese
7b3ca83329 this reconnects the new window to the existing content process 2022-04-13 06:08:07 -05:00
Mike Griese
76d8fa7b7e start thinking about moving the timers to being threadpooltimers in the core. I think every x-proc call in TermControl logs that message, so _crap_ 2022-04-12 10:53:52 -05:00
Mike Griese
9141f0419a tried to make these blindli fire_and_forgets. Didn't work 2022-04-12 10:23:27 -05:00
Mike Griese
857fb399e1 add localization back 2022-04-12 09:42:37 -05:00
Mike Griese
b3129192ad derp 2022-04-12 09:42:22 -05:00
Mike Griese
b253440cf5 add a velocity flag for this 2022-04-12 09:34:36 -05:00
Mike Griese
5429fca422 The sample works again 2022-04-12 06:53:45 -05:00
Mike Griese
46e299d2b6 Definitely needed those 2022-04-11 14:47:51 -05:00
Mike Griese
34601f7e05 more cleanup 2022-04-11 13:28:46 -05:00
Mike Griese
cf70797083 BODGY, don't raise an event on destruction, that would be too... 2022-04-11 13:28:46 -05:00
Mike Griese
07ba33b893 simplify the interface here a bit 2022-04-11 13:28:46 -05:00
Mike Griese
f818885636 move the content process main to another file as well 2022-04-11 13:28:44 -05:00
Mike Griese
738d1910da Move the content process handling to a separate file in TermControl project 2022-04-11 13:28:06 -05:00
Mike Griese
651efe248b add a dialog internally to the bounds of the control, not outside of the control 2022-04-11 13:28:04 -05:00
Mike Griese
768d4c0df3 some cleanup 2022-04-11 13:27:13 -05:00
Mike Griese
8ceb9baf9a This doesn't immediately crash, but it does crash when you start asking for the actual text ranges. That's not what you want. 2022-04-11 13:26:11 -05:00
Mike Griese
35ca313b48 Revert "This too didn't work. Creating the XAML thing not on the XAML thing isn't going to work"
This reverts commit fd364db727.
2022-04-11 13:21:55 -05:00
Mike Griese
1a78557b61 This too didn't work. Creating the XAML thing not on the XAML thing isn't going to work 2022-04-11 13:21:08 -05:00
Mike Griese
dafb627278 Revert "this was the part where I realized I dun goofed"
This reverts commit 64533c838a.
2022-04-11 13:19:22 -05:00
Mike Griese
eeb01a139d this was the part where I realized I dun goofed 2022-04-11 13:19:22 -05:00
Mike Griese
4a8f0e9562 The sample app has a hard time loading TermControl resources so we're just going to disable this for now 2022-04-11 13:19:22 -05:00
Mike Griese
ea9d3cb5f7 a fix for a crash when closing 2022-04-11 13:19:22 -05:00
Mike Griese
3d15b097b7 This works to kill the content and have the app live 2022-04-11 13:19:10 -05:00
Mike Griese
5a07282d19 Add a kill button for manually killing the content 2022-04-11 13:18:41 -05:00
Mike Griese
7e792b2b5e You know, there's 0% chance that this is the right pattern for this, but it _works_ 2022-04-11 13:18:40 -05:00
Mike Griese
c3a94454e0 some short-circuits for these inits, to make them more stable 2022-04-11 13:18:40 -05:00
Mike Griese
2f23e1fc0c A close button, and more logging 2022-04-11 13:18:40 -05:00
Mike Griese
996c71a933 Add a signal that the content can use to tell the window it's ready 2022-04-11 13:18:40 -05:00
Mike Griese
7731f5943a Some comments because everything is hard 2022-04-11 13:18:40 -05:00
Mike Griese
bb49d5086c I believe this merges the buisness of connection-factory, though there are many issues. 2022-04-11 13:18:38 -05:00
Mike Griese
e168413e9f I think this merges the-whole-thing into this branch. The remote control doesn't render right, but I think that's because the actual HEAD of all this work is in connection-factory 2022-04-11 13:17:47 -05:00
Leonard Hecker
a59e3d0c57 Fix DBCS attribute corruption during reflow (#12853)
855e136 contains a regression which breaks buffer reflow if wide surrogate
characters are present. This happens because we made use of the
`TextBufferCellIterator` whose increment operator skips 2 cells for wide
characters. This created a "misalignment" in the reflow logic which was written
for cell-wise iteration. This commit fixes the issue, by reverting back to the
previous algorithm without iterators.

Closes #12837
Closes MSFT-38904421

## Validation Steps Performed
* Run ``pwsh -noprofile -command echo "`u{D83D}`u{DE43}"``
* Resizing conhost preserves all contents 
* Resizing Windows Terminal doesn't crash it 
* Added a test covering this issue 

(cherry picked from commit 10b9044120)
Service-Card-Id: 80340091
Service-Version: Inbox
2022-04-08 12:27:16 -05:00
Mike Griese
f73da456fa Fix the OS build (#12790)
The `cascadia/` directory straight up isn't checked into the OS. So adding a test dependency on code in there was a BAD IDEA.

(cherry picked from commit 4e61be9cd7)
Service-Card-Id: 79863821
Service-Version: Inbox
2022-03-29 17:18:29 -05:00
Mike Griese
9ccd6ecd74 Manually copy trailing attributes on a resize (#12637)
## THE WHITE WHALE

This is a fairly naive fix for this bug. It's not terribly performant,
but neither is resize in the first place.

When the buffer gets resized, typically we only copy the text up to the
`MeasureRight` point, the last printable char in the row. Then we'd just
use the last char's attributes to fill the remainder of the row.

Instead, this PR changes how reflow behaves when it gets to the end of
the row. After we finish copying text, then manually walk through the
attributes at the end of the row, and copy them over. This ensures that
cells that just have a colored space in them get copied into the new
buffer as well, and we don't just blat the last character's attributes
into the rest of the row. We'll do a similar thing once we get to the
last printable char in the buffer, copying the remaining attributes.

This could DEFINITELY be more performant. I think this current
implementation walks the attrs _on every cell_, then appends the new
attrs to the new ATTR_ROW. That could be optimized by just using the
actual iterator. The copy after the last printable char bit is also
especially bad in this regard. That could likely be a blind copy - I
just wanted to get this into the world.

Finally, we now copy the final attributes to the correct buffer: the new
one.  We used to copy them to the _old_ buffer, which we were about to
destroy.

## Validation

I'll add more gifs in the morning, not enough time to finish spinning a
release Terminal build with this tonight.

Closes #32 🎉🎉🎉🎉🎉🎉🎉🎉🎉
Closes #12567

(cherry picked from commit 855e1360c0)
2022-03-28 13:33:54 -05:00
493 changed files with 16960 additions and 7624 deletions

3156
.github/fabricbot.json vendored Normal file

File diff suppressed because it is too large Load Diff

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

@@ -2,9 +2,9 @@
trigger: none
pr: none
pool:
pool:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
demands: ImageOverride -equals WinDevVS17-latest
parameters:
- name: branding
@@ -195,7 +195,6 @@ jobs:
condition: true
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /t:Terminal\CascadiaPackage /p:WindowsTerminalReleaseBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -222,7 +221,6 @@ jobs:
displayName: Build solution **\OpenConsole.sln for PublicTerminalCore
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /p:WindowsTerminalReleaseBuild=true /t:Terminal\wpf\PublicTerminalCore
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -231,7 +229,6 @@ jobs:
displayName: Build solution **\OpenConsole.sln for ConPTY
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /p:WindowsTerminalReleaseBuild=true /t:Conhost\Host_EXE;Conhost\winconpty_DLL
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
@@ -327,7 +324,7 @@ jobs:
- ${{ if eq(parameters.runCompliance, true) }}:
- template: ./templates/build-console-compliance-job.yml
- ${{ if eq(parameters.buildTerminal, true) }}:
- job: BundleAndSign
strategy:
@@ -546,7 +543,6 @@ jobs:
displayName: Build solution **\OpenConsole.sln for WPF Control
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
msbuildArgs: /p:WindowsTerminalReleaseBuild=$(UseReleaseBranding);Version=$(XES_PACKAGEVERSIONNUMBER) /t:Pack
platform: Any CPU
configuration: $(BuildConfiguration)

View File

@@ -13,7 +13,7 @@ jobs:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
demands: ImageOverride -equals WinDevVS17-latest
steps:
- checkout: self
@@ -27,7 +27,6 @@ jobs:
displayName: 'Build solution **\OpenConsole.sln'
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
msbuildArgs: ${{ parameters.additionalBuildArguments }}

View File

@@ -12,12 +12,12 @@ jobs:
BuildPlatform: ${{ parameters.platform }}
WindowsTerminalBranding: ${{ parameters.branding }}
EnableRichCodeNavigation: true
pool:
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
demands: ImageOverride -equals WinDevVS17-latest
steps:
- template: build-console-steps.yml

View File

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

View File

@@ -9,12 +9,12 @@ jobs:
variables:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
pool:
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
demands: ImageOverride -equals WinDevVS17-latest
steps:
- checkout: self
@@ -32,12 +32,11 @@ jobs:
echo VCToolsInstallDir = %VCToolsInstallDir%
echo ##vso[task.setvariable variable=VCToolsInstallDir]%VCToolsInstallDir%
displayName: 'Retrieve VC tools directory'
- task: VSBuild@1
displayName: 'Build solution **\OpenConsole.sln'
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
msbuildArgs: "${{ parameters.additionalBuildArguments }}"
@@ -88,4 +87,4 @@ jobs:
displayName: 'Publish All Build Artifacts'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'fuzzingBuildOutput'
ArtifactName: 'fuzzingBuildOutput'

View File

@@ -12,12 +12,12 @@ jobs:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
PGOBuildMode: 'Instrument'
pool:
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
demands: ImageOverride -equals WinDevVS17-latest
steps:
- template: build-console-steps.yml
@@ -34,7 +34,7 @@ jobs:
configuration: ${{ parameters.configuration }}
platform: ${{ parameters.platform }}
rerunPassesRequiredToAvoidFailure: ${{ parameters.rerunPassesRequiredToAvoidFailure }}
- template: helix-processtestresults-job.yml
parameters:
name: 'ProcessTestResults'

View File

@@ -28,7 +28,6 @@ steps:
displayName: 'Build solution **\OpenConsole.sln'
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
msbuildArgs: "${{ parameters.additionalBuildArguments }} /p:PGOBuildMode=$(PGOBuildMode) /bl:$(Build.SourcesDirectory)\\msbuild.binlog"

View File

@@ -11,12 +11,12 @@ jobs:
variables:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
pool:
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
demands: ImageOverride -equals WinDevVS17-latest
steps:
- checkout: self

View File

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

View File

@@ -16,7 +16,7 @@
<!-- 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="12.0.3" targetFramework="net45" />
<package id="Newtonsoft.Json" version="13.0.1" 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

@@ -110,7 +110,7 @@ This takes quite some time, and only generates an `msix`. It does not install th
```powershell
# If you haven't already:
Import-Module tools\OpenConsole.psm1;
Import-Module .\tools\OpenConsole.psm1;
Set-MsBuildDevEnvironment;
# The Set-MsBuildDevEnvironment call is needed for finding the path to
@@ -121,7 +121,7 @@ if ((Get-AppxPackage -Name 'WindowsTerminalDev*') -ne $null) {
Remove-AppxPackage 'WindowsTerminalDev_0.0.1.0_x64__8wekyb3d8bbwe'
};
New-Item ..\loose -Type Directory -Force;
makeappx unpack /v /o /p .\CascadiaPackage_0.0.1.0_x64_Debug.msix /d ..\Loose\;
makeappx unpack /v /o /p .\CascadiaPackage_0.0.1.0_x64_Debug.msix /d ..\loose\;
Add-AppxPackage -Path ..\loose\AppxManifest.xml -Register -ForceUpdateFromAnyVersion -ForceApplicationShutdown
```

View File

@@ -318,6 +318,7 @@
"moveFocus",
"movePane",
"swapPane",
"markMode",
"moveTab",
"multipleActions",
"newTab",
@@ -349,9 +350,11 @@
"switchToTab",
"tabSearch",
"toggleAlwaysOnTop",
"toggleBlockSelection",
"toggleFocusMode",
"selectAll",
"setFocusMode",
"switchSelectionEndpoint",
"toggleFullscreen",
"setFullScreen",
"setMaximized",
@@ -363,6 +366,10 @@
"quit",
"adjustOpacity",
"restoreLastClosed",
"addMark",
"scrollToMark",
"clearMark",
"clearAllMarks",
"unbound"
],
"type": "string"
@@ -382,6 +389,15 @@
],
"type": "string"
},
"ScrollToMarkDirection": {
"enum": [
"previous",
"next",
"first",
"last"
],
"type": "string"
},
"ResizeDirection": {
"enum": [
"left",
@@ -731,6 +747,30 @@
"direction"
]
},
"ScrollToMarkAction": {
"description": "Arguments corresponding to a Scroll to Mark Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
},
{
"properties": {
"action": {
"type": "string",
"const": "scrollToMark"
},
"direction": {
"$ref": "#/$defs/ScrollToMarkDirection",
"default": "previous",
"description": "The direction to scroll to a mark."
}
}
}
],
"required": [
"direction"
]
},
"SendInputAction": {
"description": "Arguments corresponding to a Send Input Action",
"allOf": [
@@ -838,6 +878,27 @@
}
]
},
"AddMarkAction": {
"description": "Arguments corresponding to an Add Mark Action",
"allOf": [
{
"$ref": "#/$defs/ShortcutAction"
},
{
"properties": {
"action": {
"type": "string",
"const": "addMark"
},
"color": {
"$ref": "#/$defs/Color",
"default": null,
"description": "If provided, will set the mark's color to the given value."
}
}
}
]
},
"SetColorSchemeAction": {
"description": "Arguments corresponding to a Set Color Scheme Action",
"allOf": [
@@ -1666,6 +1727,16 @@
"description": "When set to true, URLs will be detected by the Terminal. This will cause URLs to underline on hover and be clickable by pressing Ctrl.",
"type": "boolean"
},
"experimental.autoMarkPrompts": {
"default": false,
"description": "When set to true, prompts will automatically be marked.",
"type": "boolean"
},
"experimental.showMarksOnScrollbar": {
"default": false,
"description": "When set to true, marks added to the buffer via the addMark action will appear on the scrollbar.",
"type": "boolean"
},
"disableAnimations": {
"default": false,
"description": "When set to `true`, visual animations will be disabled across the application.",
@@ -2010,6 +2081,10 @@
"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/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -1,274 +0,0 @@
---
author: Mike Griese @zadjii-msft
created on: 2022-05-18
last updated: 2022-10-28
issue id: n/a
---
# Markdown Notebooks in the Terminal
## Abstract
Notebooks have risen to popularity in recent years as a way of combining both
code and documentation in a single experience. They enable users to seamlessly
write code, and execute it to see the output, write documentation on the code,
and share that with others. However, there's not really anything like notebooks
for generic commandline experiences.
There are, however, markdown files. Markdown has become a bit of a lingua franca
of the developer experience. It's used prominently on GitHub - the "homepage" of
any repo on GitHub is now typically a markdown file. This file will have all
sorts of documentation, and notably these READMEs are often filled with commands
that one can execute for this project. Downloading, installing its dependencies,
building and running the project, etc, all commands that are already listed
todcay in READMEs across the world.
It would be a major convenience for users to be able to just load a pre-rendered
markdown file directly into their terminal windows. These files already include
marked blocks of code which identify sets of commands for the command line. It
should be as simple as clicking a button to run these commands in the Terminal,
or even to run a whole file worth of commands automatically.
## Background
### Inspiration
[Jupyter notebooks] ([a Jupyter example]) served as the primary inspiration for
this feature. Another shoutout to [this comment on HackerNews], which inspired a
lot of brainstorming on this topic over the last year since it was posted.
Many initial brainstorms were focused on more notebook-like features in the
Terminal. For example, finding ways to create individual terminal blocks inline
with commands, where each input command and its output would be separated from
one another, possibly separated by some sort of text/rich markup. This seemed to
precipitate the need for a new file syntax to be authored, where we could save
commands as they were run. The Terminal would then open this new file type as a
set of terminal blocks each pre-populated with these saved commands. Hoever,
this came with the drawback that projects which would like to leverage this
feature would have to author entirely new files, in a new syntax, just to make
use of this functionality. It seemed as though it was a niche enough UX that it
would be unlikely to broadly catch on.
The real inspiration here was that there's already a file type with broad
adoption that's already filled with commands like this. Markdown files. Take a
look at something like [building.md](../../../building.md). That file _already_
has a long set of commands for building the Terminal, running tests, deploying,
and various other helper scripts. Being able to immediately leverage this
existing ecosystem would undobtably lead to quicker adoption.
### User Stories
* **A**: The user can perform some commandline action (like `wt open
README.md`), which opens a new pane in the Terminal, with the markdown file
rendered into that pane.
* **B**: Markdown panes have buttons next to code blocks that allow the text of
that block to be sent directly to the adjacent terminal as input.
* **C**: The user can press different buttons to run some subset of all the
commands in the file
- **C.1**: Run all the commands in this file
- **C.2**: Run all the commands from (the currently selected block) to the end
of the file
- **C.1**: Run all the commands from (the currently selected block) to the
next header. (e.g., run all the commands in this section of the doc.)
* **D**: The user can edit the contents of the markdown file directly in the
Terminal.
* **E**: The Terminal could be configured to automatically open a markdown file
when `cd`ing to a directory
* **F**: The command for opening a markdown file also supports opening files
from the web (e.g. directly from GitHub)
* **G**: Code blocks in the markdown file are automatically assigned
autoincrementing IDs. The user can perform an action (via keybinding, command
palette, whatever) to execute a command block from the file, based on it's
assigned ID.
* **H**: ...
## Solution Design
The Terminal will allow for non-terminal content in a pane. This is something
that's been prototyped before, just needs a stronger justification for
finishing.
We'll leverage the Terminal's existing `sendInput` command to handle a lot of
this. That can be used to send keystrokes to the Terminal. Figuring out which
pane to send the `sendInput` command to might be a bit tricky. We'll need to
figure out what an action like that does when the active pane is not a terminal
pane.
Below are two different structures that could be used for imlpementing notebooks
in the Terminal. These are **Side-by-side** notebooks, and **Inline** notebooks.
Side-by-side notebooks consist of two panes - a standard terminal control in
one, and rendered markdown in the other. Inline notebooks are more like
traditional notebooks, with the terminal output rendered as a block within the
rendered markdown content.
### Side-by-side notebooks
Opening Markdown side-by-side with the Terminal output is certainly a little
different than the way a notebook traditionally works. Notebooks typically have
the code in a block, with output inline, below the block. Blocks could also just
be dedicated to text, for documentation mixed between the code. The feature
proposed here is different from that, for sure. For this proposal, the Terminal
still exists side-by-side from the source markdown. Running commands from the
markdown text would then send the command as a string of input to the connected
terminal. This approach was elected over attempting to create artificial
boundaries between different blocks.
Oftentimes, the command line is a very stateful experience. Set some environment
variables, run some script, use the errorlevel from the previous command, etc.
Running each block in wholly separate console instances would likely not be
useful.
Additionally, finding the separation between command line input and its output,
and the separation between individual commands is not an entirely trivial
process. Should we try to separate out the command input line into one buffer,
then the output into another buffer sounds great on paper. Consider, however,
something like `cmd.exe`, which does not provide any sort of distinction between
its input line and its output. Or `python.exe`, as an interactive REPL, which
certainly doesn't tell the terminal the difference. How would we be able to
detect something like a multi-line command at the REPL?
By keeing the command blocks out-of-band from the terminal output, we keep the
familiar terminal experience. It acts just as you'd expect, with no additional
configuration on the user's side. The commands are something that are already
written down, just waiting for the user to run them. They could even be sent to
something that isn't necessarily a shell - like pasting a bit of configuration
into a text editor like `vim` or `emacs`. The commands in the markdown side are
just strings of text to send to the terminal side - nothing more.
### Inline notebooks
Is there a way to have a more traditional notebook experience, where the
terminal output is rendered as blocks within the markdown itself? I believe
there is, by making agressive use of the FTCS mark VT sequences. These are
sequences that enable identifying the parts of the buffer as a prompt, the
commandline, or the output. We can use these to pull out individual rows of the
buffer, and display them as miniature terminal controls within the notebook.
This involves a single terminal insance backing the entire notebook. When the
user runs a code block in the notebook, we'll `sendInput` the text to the
backing terminal the same as before. We'll then use the `FTCS_COMMAND_EXECUTED`
sequence to know where the actual start of the output of the command is. We'll
gather all output from that moment on, and tee that to a separate "front"
control, which we use as the display for the output of the command. We'll render
that "front" control inline with the rest of the markdown content, immediately
below the code block for that command.
## UI/UX Design
### Side-by-side
![A rough mockup of what this feature might look like](./mockup-000.png)
### Inline
![](./inline-blocks-000.png)
## Tenents
<table>
<tr><td><strong>Accessibility</strong></td><td>
[comment]: # How will the proposed change impact accessibility for users of screen readers, assistive input devices, etc.
</td></tr>
<tr><td><strong>Security</strong></td><td>
[comment]: # How will the proposed change impact security?
Opening a file like this will _never_ auto-run commands. Commands must always be
intentionally interacted with, to provide a positive confirmation from the user
"yes, I intended to run `curl some.website.com/foo.txt`".
</td></tr>
<tr><td><strong>Reliability</strong></td><td>
[comment]: # Will the proposed change improve reliability? If not, why make the change?
</td></tr>
<tr><td><strong>Compatibility</strong></td><td>
[comment]: # Will the proposed change break existing code/behaviors? If so, how, and is the breaking change "worth it"?
It's critically important that nothing about this feature be necessarily Windows
Terminal-dependent. These features shouldn't be powered by some new undocumented
escape sequence that only we support. They should NOT be powered by new Windows
APIs, especially not any extensions to the Console API. There's no reason other
terminals couldn't also implement similar functionality.
</td></tr>
<tr><td><strong>Performance, Power, and Efficiency</strong></td><td>
[comment]: # Will the proposed change break existing code/behaviors? If so, how, and is the breaking change "worth it"?
</td></tr>
</table>
## Potential Issues
For rendering markdown, we'll either need:
* A way to display a WebView in a WinUI2 XAML Island
- This is something that's on the backlog currently for MUX 2.x. Theoretically
not too hard to add an `IInitializeWithWindow` to `WebView2` which should
enable XAML Islands, but needs more research.
* To migrate to WinUI 3
- In WinUI 3 I believe we should be able to get WebViews for free.
- We might still be a XAML Island in WinUI 3, which may complicate that.
* A C++ based method of rendering Markdown to UWP XAML
- There's a Windows Community Toolkit control for rendering to XAML currently,
but that is backed by C#, so we can't use that.
We'll also need the markdown rendering to be extensible, so that we can insert
"play" buttons alongside the blocks.
## Future considerations
### Tighter GitHub integration
GitHub already has the helpful "Open In GitHub" button for opening a repo in the
GitHub desktop client, or in Visual Studio.
![GitHub's "Clone, open or download" flyout](GitHub-open-with.png)
It'd be cool if there was a similar button for opening it up in the Terminal. It
could open the README immediately as a new tab, and then provide some sort of
InfoBar with a button that would allow the user to immediately clone the repo to
some location on their PC. This would likely need a protocol handler installed
by the Terminal to help connect the browser to the Terminal.
### Collapsible Blocks
One of the key features of notebooks is the ability to easily collapse regions
of the notebook. With the command output being out of band from the input of the
command, not as independent blocks, this becomes a bit trickier. To try and
reproduce a similar ability to collapse regions of the buffer, we'll look to
[Marks] in the terminal as a potential solution. The FinalTerm sequences allow a
client to mark up the region of the buffer that's the prompt, the command line,
and the output. Using those marks would provide an easy heuristic to allow users
to collapse the output of commands. These sequences however do require manual
configuration by the user, and are not expected to be able to work in all
environments (and shells). While powerful, because of this limitation, we didn't
want to architect the entire experience around something that wouldn't always
work.
## Resources
[comment]: # Be sure to add links to references, resources, footnotes, etc.
### Footnotes
<a name="footnote-1"><a>[1]:
[Jupyter notebooks]: https://jupyter.org/
[a Jupyter example]: https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb
[this comment on HackerNews]: https://news.ycombinator.com/item?id=26617656
[Marks]: https://github.com/microsoft/terminal/issues/11000

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 868 KiB

View File

@@ -3,9 +3,11 @@
#include "pch.h"
#include "MyPage.h"
#include "MySettings.h"
#include <LibraryResources.h>
#include "MyPage.g.cpp"
#include "MySettings.h"
#include "..\..\..\src\cascadia\UnitTests_Control\MockControlSettings.h"
#include "..\..\..\src\types\inc\utils.hpp"
using namespace std::chrono_literals;
using namespace winrt::Microsoft::Terminal;
@@ -26,7 +28,7 @@ namespace winrt::SampleApp::implementation
void MyPage::Create()
{
auto settings = winrt::make_self<implementation::MySettings>();
auto settings = winrt::make_self<MySettings>();
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This TermControl is hosted in-proc...",
winrt::hstring{},
@@ -44,6 +46,216 @@ namespace winrt::SampleApp::implementation
Control::TermControl control{ *settings, *settings, conn };
InProcContent().Children().Append(control);
// Once the control loads (and not before that), write some text for debugging:
control.Initialized([conn](auto&&, auto&&) {
conn.WriteInput(L"This TermControl is hosted in-proc...");
});
}
static wil::unique_process_information _createHostClassProcess(const winrt::guid& g)
{
auto guidStr{ ::Microsoft::Console::Utils::GuidToString(g) };
// Create an event that the content process will use to signal it is
// ready to go. We won't need the event after this function, so the
// unique_event will clean up our handle when we leave this scope. The
// ContentProcess is responsible for cleaning up its own handle.
wil::unique_event ev{ CreateEvent(nullptr, true, false, nullptr) };
// Make sure to mark this handle as inheritable! Even with
// bInheritHandles=true, this is only inherited when it's explicitly
// allowed to be.
SetHandleInformation(ev.get(), HANDLE_FLAG_INHERIT, 1);
// god bless, fmt::format will format a HANDLE like `0xa80`
std::wstring commandline{
fmt::format(L"WindowsTerminal.exe --content {} --signal {}", guidStr, ev.get())
};
STARTUPINFO siOne{ 0 };
siOne.cb = sizeof(STARTUPINFOW);
wil::unique_process_information piOne;
auto succeeded = CreateProcessW(
nullptr,
commandline.data(),
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
true, // bInheritHandles
CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
nullptr, // lpEnvironment
nullptr, // startingDirectory
&siOne, // lpStartupInfo
&piOne // lpProcessInformation
);
THROW_IF_WIN32_BOOL_FALSE(succeeded);
// Wait for the child process to signal that they're ready.
WaitForSingleObject(ev.get(), INFINITE);
return piOne;
}
winrt::fire_and_forget MyPage::_writeToLog(std::wstring_view str)
{
winrt::hstring copy{ str };
// Switch back to the UI thread.
co_await resume_foreground(Dispatcher());
winrt::WUX::Controls::TextBlock block;
block.Text(copy);
Log().Children().Append(block);
}
winrt::fire_and_forget MyPage::CreateClicked(const IInspectable& sender,
const WUX::Input::TappedRoutedEventArgs& eventArgs)
{
auto guidString = GuidInput().Text();
// Capture calling context.
winrt::apartment_context ui_thread;
auto canConvert = guidString.size() == 38 &&
guidString.front() == '{' &&
guidString.back() == '}';
bool tryingToAttach = false;
winrt::guid contentGuid{ ::Microsoft::Console::Utils::CreateGuid() };
if (canConvert)
{
GUID result{};
if (SUCCEEDED(IIDFromString(guidString.c_str(), &result)))
{
contentGuid = result;
tryingToAttach = true;
}
}
_writeToLog(tryingToAttach ? L"Attaching to existing content process" : L"Creating new content process");
co_await winrt::resume_background();
if (!tryingToAttach)
{
// Spawn a wt.exe, with the guid on the commandline
piContentProcess = std::move(_createHostClassProcess(contentGuid));
}
// THIS MUST TAKE PLACE AFTER _createHostClassProcess.
// * If we're creating a new OOP control, _createHostClassProcess will
// spawn the process that will actually host the ContentProcess
// object.
// * If we're attaching, then that process already exists.
Control::ContentProcess content{ nullptr };
try
{
content = create_instance<Control::ContentProcess>(contentGuid, CLSCTX_LOCAL_SERVER);
}
catch (winrt::hresult_error hr)
{
_writeToLog(L"CreateInstance the ContentProcess object");
_writeToLog(fmt::format(L" HR ({}): {}", hr.code(), hr.message().c_str()));
co_return; // be sure to co_return or we'll fall through to the part where we clear the log
}
if (content == nullptr)
{
_writeToLog(L"Failed to connect to the ContentProcess object. It may not have been started fast enough.");
co_return; // be sure to co_return or we'll fall through to the part where we clear the log
}
TerminalConnection::ConnectionInformation connectInfo{ nullptr };
Control::IControlSettings settings{ *winrt::make_self<implementation::MySettings>() };
// When creating a terminal for the first time, pass it a connection
// info
//
// otherwise, when attaching to an existing one, just pass null, because
// we don't need the connection info.
if (!tryingToAttach)
{
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This TermControl is hosted out-of-proc...",
winrt::hstring{},
L"",
nullptr,
32,
80,
winrt::guid()) };
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
connectInfo = TerminalConnection::ConnectionInformation(myClass, connectionSettings);
if (!content.Initialize(settings, settings, connectInfo))
{
_writeToLog(L"Failed to Initialize the ContentProcess object.");
co_return; // be sure to co_return or we'll fall through to the part where we clear the log
}
}
else
{
// If we're attaching, we don't really need to do anything special.
}
// Switch back to the UI thread.
co_await ui_thread;
// Create the XAML control that will be attached to the content process.
// We're not passing in a connection, because the contentGuid will be used instead.
Control::TermControl control{ contentGuid, settings, settings, nullptr };
auto weakControl = winrt::make_weak(control);
control.RaiseNotice([this](auto&&, auto& args) {
_writeToLog(L"Content process died, probably.");
_writeToLog(args.Message());
OutOfProcContent().Children().Clear();
GuidInput().Text(L"");
if (piContentProcess.hProcess)
{
piContentProcess.reset();
}
});
control.ConnectionStateChanged([this, weakControl](auto&&, auto&) {
if (auto strongControl{ weakControl.get() })
{
const auto newConnectionState = strongControl.ConnectionState();
if (newConnectionState == TerminalConnection::ConnectionState::Closed)
{
_writeToLog(L"Connection was closed");
OutOfProcContent().Children().Clear();
GuidInput().Text(L"");
if (piContentProcess.hProcess)
{
piContentProcess.reset();
}
}
}
});
Log().Children().Clear();
OutOfProcContent().Children().Append(control);
if (!tryingToAttach)
{
auto guidStr{ ::Microsoft::Console::Utils::GuidToString(contentGuid) };
GuidInput().Text(guidStr);
}
}
void MyPage::CloseClicked(const IInspectable& /*sender*/,
const WUX::Input::TappedRoutedEventArgs& /*eventArgs*/)
{
OutOfProcContent().Children().Clear();
GuidInput().Text(L"");
if (piContentProcess.hProcess)
{
piContentProcess.reset();
}
}
void MyPage::KillClicked(const IInspectable& /*sender*/,
const WUX::Input::TappedRoutedEventArgs& /*eventArgs*/)
{
if (piContentProcess.hProcess)
{
TerminateProcess(piContentProcess.hProcess, (UINT)-1);
piContentProcess.reset();
}
}
// Method Description:

View File

@@ -14,11 +14,18 @@ namespace winrt::SampleApp::implementation
MyPage();
void Create();
hstring Title();
winrt::fire_and_forget CreateClicked(const IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& eventArgs);
void CloseClicked(const IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& eventArgs);
void KillClicked(const IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& eventArgs);
private:
friend struct MyPageT<MyPage>; // for Xaml to bind events
wil::unique_process_information piContentProcess;
winrt::fire_and_forget _writeToLog(std::wstring_view str);
};
}

View File

@@ -23,9 +23,23 @@
<TextBox x:Name="GuidInput"
Width="400"
PlaceholderText="{}{guid here}" />
<Button Grid.Row="0">
<Button x:Name="CreateOutOfProcControl"
Grid.Row="0"
Tapped="CreateClicked">
Create
</Button>
<Button x:Name="CloseOutOfProcControl"
Grid.Row="0"
Margin="4,0,0,0"
Tapped="CloseClicked">
Close
</Button>
<Button x:Name="KillOutOfProcControl"
Grid.Row="0"
Margin="4,0,0,0"
Tapped="KillClicked">
Kill
</Button>
</StackPanel>
@@ -46,14 +60,26 @@
VerticalAlignment="Stretch"
Background="#ff0000" />
<Grid x:Name="OutOfProcContent"
Grid.Column="1"
Padding="16"
<Grid Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#0000ff" />
VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel x:Name="Log"
Grid.Row="0"
Orientation="Vertical" />
<Grid x:Name="OutOfProcContent"
Grid.Row="1"
Padding="16"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#0000ff" />
</Grid>
</Grid>

View File

@@ -17,9 +17,15 @@
<DisableEmbeddedXbf>false</DisableEmbeddedXbf>
<XamlComponentResourceLocation>nested</XamlComponentResourceLocation>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<ItemDefinitionGroup>
<ClCompile>
@@ -147,14 +153,15 @@
<!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<!-- 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="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\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.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<!--

View File

@@ -11,9 +11,13 @@
<!-- sets a bunch of Windows Universal properties -->
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
</PropertyGroup>
<Import Project="..\..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<!-- ========================= XAML files ======================== -->
<ItemGroup>
<!-- DON'T PUT XAML FILES HERE! Put them in SampleAppLib.vcxproj -->
@@ -81,13 +85,11 @@
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.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.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
</Target>
<ItemDefinitionGroup>
@@ -102,4 +104,7 @@
</Link>
</ItemDefinitionGroup>
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<!-- 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" />
</Project>

View File

@@ -57,8 +57,8 @@ void SampleIslandWindow::MakeWindow() noexcept
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
1024,
860,
nullptr,
nullptr,
wc.hInstance,
@@ -104,8 +104,6 @@ void SampleIslandWindow::_HandleCreateWindow(const WPARAM, const LPARAM lParam)
void SampleIslandWindow::Initialize()
{
const bool initialized = (_interopWindowHandle != nullptr);
_source = DesktopWindowXamlSource{};
auto interop = _source.as<IDesktopWindowXamlSourceNative>();

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
<PropertyGroup Label="Globals">
<ProjectGuid>{b4427499-9fde-4208-b456-5bc580637633}</ProjectGuid>
@@ -16,7 +15,15 @@
<TargetPlatformIdentifier>Windows</TargetPlatformIdentifier>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>
<TerminalXamlApplicationToolkit>true</TerminalXamlApplicationToolkit>
<TerminalVCRTForwarders>true</TerminalVCRTForwarders>
<TerminalThemeHelpers>true</TerminalThemeHelpers>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
<Import Project="$(OpenConsoleDir)src\common.nugetversions.props" />
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<ItemDefinitionGroup>
@@ -138,16 +145,11 @@
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
<Import Project="..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets" Condition="Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.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.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.3\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
<Error Condition="!Exists('..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.VCRTForwarders.140.1.0.4\build\native\Microsoft.VCRTForwarders.140.targets'))" />
</Target>
<!-- Override GetPackagingOutputs to roll up all our dependencies.
@@ -225,13 +227,24 @@
<TargetPath>%(Filename)%(Extension)</TargetPath>
</PackagingOutputs>
</ItemGroup>
<!-- Same thing AGAIN here, with OpenConsole.exe If you forget this, then
the scratch app will use the inbox conpty with a newer conpty lib, causing
us to send the inbox conhost messages that will make it explode. -->
<ItemGroup>
<_OpenConsoleExe Include="$(OpenConsoleCommonOutDir)\OpenConsole.exe" />
<PackagingOutputs Include="@(_OpenConsoleExe)">
<ProjectName>$(ProjectName)</ProjectName>
<OutputGroup>BuiltProjectOutputGroup</OutputGroup>
<TargetPath>%(Filename)%(Extension)</TargetPath>
</PackagingOutputs>
</ItemGroup>
</Target>
<Import Project="$(OpenConsoleDir)\build\rules\GenerateSxsManifestsFromWinmds.targets" />
<Import Project="..\..\..\packages\Terminal.ThemeHelpers.0.2.200324001\build\native\Terminal.ThemeHelpers.targets" Condition="Exists('..\..\..\packages\Terminal.ThemeHelpers.0.2.200324001\build\native\Terminal.ThemeHelpers.targets')" />
<!-- 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" />
</Project>

2
src/audio/dirs Normal file
View File

@@ -0,0 +1,2 @@
DIRS=midi \

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;
};

2
src/audio/midi/dirs Normal file
View File

@@ -0,0 +1,2 @@
DIRS=lib \

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,8 @@
!include ..\sources.inc
# -------------------------------------
# Program Information
# -------------------------------------
TARGETNAME = ConAudioMidi
TARGETTYPE = LIBRARY

View File

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

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

@@ -0,0 +1,31 @@
/*++
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>
#include <mmeapi.h>
// clang-format on

View File

@@ -0,0 +1,28 @@
!include ..\..\..\project.inc
# -------------------------------------
# Windows Console
# - Console Audio Functions
# -------------------------------------
# -------------------------------------
# Build System Settings
# -------------------------------------
# Code in the OneCore depot automatically excludes default Win32 libraries.
# -------------------------------------
# Sources, Headers, and Libraries
# -------------------------------------
PRECOMPILED_CXX = 1
PRECOMPILED_INCLUDE = ..\precomp.h
SOURCES = \
..\MidiAudio.cpp \
INCLUDES = \
$(INCLUDES); \
..; \
..\..\..\inc; \
$(MINWIN_INTERNAL_PRIV_SDK_INC_PATH_L); \

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

@@ -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 (target >= limit)
{
// 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 (target >= limit)
{
return target;
}
if (accessibilityMode)
{
return _GetWordEndForAccessibility(target, wordDelimiters, limit.to_win32_coord());
return _GetWordEndForAccessibility(target, wordDelimiters, limit);
}
else
{
@@ -1274,19 +1270,19 @@ 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 };
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
if (target >= limit)
{
// if we're already on/past the last RegularChar,
// clamp result to that position
@@ -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 (copy >= limit)
{
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 (resultPos > limit)
{
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 (resultPos > limit)
{
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,34 @@ 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() }) };
bool pastEndInclusive;
til::point limit;
{
// if the limit is past the end of the buffer,
// 1) clamp limit to end of buffer
// 2) set pastEndInclusive
const auto endInclusive{ bufferSize.BottomRightInclusive() };
const auto val = limitOptional.value_or(endInclusive);
pastEndInclusive = val > endInclusive;
limit = pastEndInclusive ? endInclusive : val;
}
const auto distanceToLimit{ bufferSize.CompareInBounds(pos.to_win32_coord(), limit.to_win32_coord(), true) };
const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit) + (pastEndInclusive ? 1 : 0) };
if (distanceToLimit >= 0)
{
// Corner Case: we're on/past the limit
@@ -1547,7 +1553,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 +1562,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 (pos > limit)
{
// we're past the end
// clamp us to the limit
@@ -1588,7 +1594,7 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point>
bufferSize.DecrementInBounds(resultPos, true);
}
pos = til::point{ resultPos };
pos = resultPos;
return success;
}
@@ -1606,24 +1612,24 @@ 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();
// (0,0) is the top-left of the screen
// the physically "higher" coordinate is closer to the top-left
// the physically "lower" coordinate is closer to the bottom-right
const auto [higherCoord, lowerCoord] = bufferSize.CompareInBounds(start, end) <= 0 ?
const auto [higherCoord, lowerCoord] = start <= end ?
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 +1667,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 +1714,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 +1731,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 +2249,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 +2302,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 +2445,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 +2699,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 +2724,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 +2747,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

@@ -135,6 +135,10 @@
<!-- 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>

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

@@ -41,6 +41,7 @@
<ClCompile Include="DeserializationTests.cpp" />
<ClCompile Include="SerializationTests.cpp" />
<ClCompile Include="TerminalSettingsTests.cpp" />
<ClCompile Include="ThemeTests.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>

View File

@@ -0,0 +1,281 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "../TerminalSettingsModel/Theme.h"
#include "../TerminalSettingsModel/CascadiaSettings.h"
#include "../types/inc/colorTable.hpp"
#include "JsonTestClass.h"
#include <defaults.h>
using namespace Microsoft::Console;
using namespace winrt::Microsoft::Terminal;
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
namespace SettingsModelLocalTests
{
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
// an updated TAEF that will let us install framework packages when the test
// package is deployed. Until then, these tests won't deploy in CI.
class ThemeTests : public JsonTestClass
{
// Use a custom AppxManifest to ensure that we can activate winrt types
// from our test. This property will tell taef to manually use this as
// the AppxManifest for this test class.
// This does not yet work for anything XAML-y. See TabTests.cpp for more
// details on that.
BEGIN_TEST_CLASS(ThemeTests)
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS()
TEST_METHOD(ParseSimpleTheme);
TEST_METHOD(ParseEmptyTheme);
TEST_METHOD(ParseNoWindowTheme);
TEST_METHOD(ParseNullWindowTheme);
TEST_METHOD(ParseThemeWithNullThemeColor);
TEST_METHOD(InvalidCurrentTheme);
static Core::Color rgb(uint8_t r, uint8_t g, uint8_t b) noexcept
{
return Core::Color{ r, g, b, 255 };
}
static Core::Color rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
{
return Core::Color{ r, g, b, a };
}
};
void ThemeTests::ParseSimpleTheme()
{
static constexpr std::string_view orangeTheme{ R"({
"name": "orange",
"tabRow":
{
"background": "#FFFF8800",
"unfocusedBackground": "#FF8844"
},
"window":
{
"applicationTheme": "light",
"useMica": true
}
})" };
const auto schemeObject = VerifyParseSucceeded(orangeTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"orange", theme->Name());
VERIFY_IS_NOT_NULL(theme->TabRow());
VERIFY_IS_NOT_NULL(theme->TabRow().Background());
VERIFY_ARE_EQUAL(Settings::Model::ThemeColorType::Color, theme->TabRow().Background().ColorType());
VERIFY_ARE_EQUAL(rgba(0xff, 0xff, 0x88, 0x00), theme->TabRow().Background().Color());
VERIFY_ARE_EQUAL(rgba(0xff, 0x88, 0x44, 0xff), theme->TabRow().UnfocusedBackground().Color());
VERIFY_IS_NOT_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Light, theme->Window().RequestedTheme());
VERIFY_ARE_EQUAL(true, theme->Window().UseMica());
}
void ThemeTests::ParseEmptyTheme()
{
Log::Comment(L"This theme doesn't have any elements defined.");
static constexpr std::string_view emptyTheme{ R"({
"name": "empty"
})" };
const auto schemeObject = VerifyParseSucceeded(emptyTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"empty", theme->Name());
VERIFY_IS_NULL(theme->TabRow());
VERIFY_IS_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Default, theme->RequestedTheme());
}
void ThemeTests::ParseNoWindowTheme()
{
Log::Comment(L"This theme doesn't have a window defined.");
static constexpr std::string_view emptyTheme{ R"({
"name": "noWindow",
"tabRow":
{
"background": "#112233",
"unfocusedBackground": "#FF884400"
},
})" };
const auto schemeObject = VerifyParseSucceeded(emptyTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"noWindow", theme->Name());
VERIFY_IS_NOT_NULL(theme->TabRow());
VERIFY_IS_NOT_NULL(theme->TabRow().Background());
VERIFY_ARE_EQUAL(Settings::Model::ThemeColorType::Color, theme->TabRow().Background().ColorType());
VERIFY_ARE_EQUAL(rgb(0x11, 0x22, 0x33), theme->TabRow().Background().Color());
VERIFY_IS_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Default, theme->RequestedTheme());
}
void ThemeTests::ParseNullWindowTheme()
{
Log::Comment(L"This theme doesn't have a window defined.");
static constexpr std::string_view emptyTheme{ R"({
"name": "nullWindow",
"tabRow":
{
"background": "#112233",
"unfocusedBackground": "#FF884400"
},
"window": null
})" };
const auto schemeObject = VerifyParseSucceeded(emptyTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"nullWindow", theme->Name());
VERIFY_IS_NOT_NULL(theme->TabRow());
VERIFY_IS_NOT_NULL(theme->TabRow().Background());
VERIFY_ARE_EQUAL(Settings::Model::ThemeColorType::Color, theme->TabRow().Background().ColorType());
VERIFY_ARE_EQUAL(rgb(0x11, 0x22, 0x33), theme->TabRow().Background().Color());
VERIFY_IS_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Default, theme->RequestedTheme());
}
void ThemeTests::ParseThemeWithNullThemeColor()
{
Log::Comment(L"These themes are all missing a tabRow background. Make sure we don't somehow default-construct one for them");
static constexpr std::string_view settingsString{ R"json({
"themes": [
{
"name": "backgroundEmpty",
"tabRow":
{
},
"window":
{
"applicationTheme": "light",
"useMica": true
}
},
{
"name": "backgroundNull",
"tabRow":
{
"background": null
},
"window":
{
"applicationTheme": "light",
"useMica": true
}
},
{
"name": "backgroundOmittedEntirely",
"window":
{
"applicationTheme": "light",
"useMica": true
}
}
]
})json" };
try
{
const auto settings{ winrt::make_self<CascadiaSettings>(settingsString, DefaultJson) };
const auto& themes{ settings->GlobalSettings().Themes() };
{
const auto& backgroundEmpty{ themes.Lookup(L"backgroundEmpty") };
VERIFY_ARE_EQUAL(L"backgroundEmpty", backgroundEmpty.Name());
VERIFY_IS_NOT_NULL(backgroundEmpty.TabRow());
VERIFY_IS_NULL(backgroundEmpty.TabRow().Background());
}
{
const auto& backgroundNull{ themes.Lookup(L"backgroundNull") };
VERIFY_ARE_EQUAL(L"backgroundNull", backgroundNull.Name());
VERIFY_IS_NOT_NULL(backgroundNull.TabRow());
VERIFY_IS_NULL(backgroundNull.TabRow().Background());
}
{
const auto& backgroundOmittedEntirely{ themes.Lookup(L"backgroundOmittedEntirely") };
VERIFY_ARE_EQUAL(L"backgroundOmittedEntirely", backgroundOmittedEntirely.Name());
VERIFY_IS_NULL(backgroundOmittedEntirely.TabRow());
}
}
catch (const SettingsException& ex)
{
auto loadError = ex.Error();
loadError;
throw ex;
}
catch (const SettingsTypedDeserializationException& e)
{
auto deserializationErrorMessage = til::u8u16(e.what());
Log::Comment(NoThrowString().Format(deserializationErrorMessage.c_str()));
throw e;
}
}
void ThemeTests::InvalidCurrentTheme()
{
Log::Comment(L"Make sure specifying an invalid theme falls back to a sensible default.");
static constexpr std::string_view settingsString{ R"json({
"theme": "foo",
"themes": [
{
"name": "bar",
"tabRow": {},
"window":
{
"applicationTheme": "light",
"useMica": true
}
}
]
})json" };
try
{
const auto settings{ winrt::make_self<CascadiaSettings>(settingsString, DefaultJson) };
VERIFY_ARE_EQUAL(1u, settings->Warnings().Size());
VERIFY_ARE_EQUAL(Settings::Model::SettingsLoadWarnings::UnknownTheme, settings->Warnings().GetAt(0));
const auto& themes{ settings->GlobalSettings().Themes() };
{
const auto& bar{ themes.Lookup(L"bar") };
VERIFY_ARE_EQUAL(L"bar", bar.Name());
VERIFY_IS_NOT_NULL(bar.TabRow());
VERIFY_IS_NULL(bar.TabRow().Background());
}
const auto currentTheme{ settings->GlobalSettings().CurrentTheme() };
VERIFY_IS_NOT_NULL(currentTheme);
VERIFY_ARE_EQUAL(L"system", currentTheme.Name());
}
catch (const SettingsException& ex)
{
auto loadError = ex.Error();
loadError;
throw ex;
}
catch (const SettingsTypedDeserializationException& e)
{
auto deserializationErrorMessage = til::u8u16(e.what());
Log::Comment(NoThrowString().Format(deserializationErrorMessage.c_str()));
throw e;
}
}
}

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

@@ -1036,4 +1036,26 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
return winrt::single_threaded_vector(std::move(vec));
}
void Monarch::RequestMoveContent(winrt::hstring window,
winrt::hstring content,
uint32_t tabIndex)
{
auto windowId = _lookupPeasantIdForName(window);
if (windowId == 0)
{
/* TODO! try the name as an integer ID */
return;
}
if (auto targetPeasant{ _getPeasant(windowId) })
{
auto request = winrt::make_self<implementation::AttachRequest>(content, tabIndex);
targetPeasant.AttachContentToWindow(*request);
}
else
{
/*TODO! log */
}
}
}

View File

@@ -60,6 +60,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Terminal::Remoting::PeasantInfo> GetPeasantInfos();
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
void RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex);
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);

View File

@@ -60,6 +60,8 @@ namespace Microsoft.Terminal.Remoting
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos { get; };
Windows.Foundation.Collections.IVector<String> GetAllWindowLayouts();
void RequestMoveContent(String window, String content, UInt32 tabIndex);
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;

View File

@@ -8,6 +8,7 @@
#include "GetWindowLayoutArgs.h"
#include "Peasant.g.cpp"
#include "../../types/inc/utils.hpp"
#include "AttachRequest.g.cpp"
using namespace winrt;
using namespace winrt::Microsoft::Terminal;
@@ -275,6 +276,22 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
void Peasant::AttachContentToWindow(Remoting::AttachRequest request)
{
try
{
_AttachRequestedHandlers(*this, request);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
TraceLoggingWrite(g_hRemotingProvider,
"Peasant_AttachContentToWindow",
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
}
void Peasant::Quit()
{
try

View File

@@ -5,6 +5,7 @@
#include "Peasant.g.h"
#include "RenameRequestArgs.h"
#include "AttachRequest.g.h"
namespace RemotingUnitTests
{
@@ -12,6 +13,18 @@ namespace RemotingUnitTests
};
namespace winrt::Microsoft::Terminal::Remoting::implementation
{
struct AttachRequest : public AttachRequestT<AttachRequest>
{
WINRT_PROPERTY(winrt::hstring, Content);
WINRT_PROPERTY(uint32_t, TabIndex);
public:
AttachRequest(winrt::hstring content,
uint32_t tabIndex) :
_Content{ content },
_TabIndex{ tabIndex } {};
};
struct Peasant : public PeasantT<Peasant>
{
Peasant();
@@ -32,6 +45,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void RequestQuitAll();
void Quit();
void AttachContentToWindow(Remoting::AttachRequest request);
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
@@ -47,12 +62,15 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
private:
Peasant(const uint64_t testPID);
uint64_t _ourPID;

View File

@@ -52,6 +52,11 @@ namespace Microsoft.Terminal.Remoting
MonitorBehavior ToMonitor;
}
[default_interface] runtimeclass AttachRequest {
String Content { get; };
UInt32 TabIndex { get; };
}
interface IPeasant
{
CommandlineArgs InitialArgs { get; };
@@ -70,23 +75,31 @@ namespace Microsoft.Terminal.Remoting
void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested
void RequestRename(RenameRequestArgs args); // Tells us to raise a RenameRequested
void Summon(SummonWindowBehavior behavior);
void RequestShowNotificationIcon();
void RequestHideNotificationIcon();
void RequestQuitAll();
void Quit();
String GetWindowLayout();
void AttachContentToWindow(AttachRequest request);
event Windows.Foundation.TypedEventHandler<Object, WindowActivatedArgs> WindowActivated;
event Windows.Foundation.TypedEventHandler<Object, CommandlineArgs> ExecuteCommandlineRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> DisplayWindowIdRequested;
event Windows.Foundation.TypedEventHandler<Object, RenameRequestArgs> RenameRequested;
event Windows.Foundation.TypedEventHandler<Object, SummonWindowBehavior> SummonRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> ShowNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> HideNotificationIconRequested;
event Windows.Foundation.TypedEventHandler<Object, GetWindowLayoutArgs> GetWindowLayoutRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitAllRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
event Windows.Foundation.TypedEventHandler<Object, AttachRequest> AttachRequested;
};
[default_interface] runtimeclass Peasant : IPeasant

View File

@@ -788,4 +788,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
}
return nullptr;
}
winrt::fire_and_forget WindowManager::RequestMoveContent(winrt::hstring window,
winrt::hstring content,
uint32_t tabIndex)
{
co_await winrt::resume_background();
_monarch.RequestMoveContent(window, content, tabIndex);
}
}

View File

@@ -48,9 +48,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
winrt::fire_and_forget RequestHideNotificationIcon();
winrt::fire_and_forget RequestQuitAll();
bool DoesQuakeWindowExist();
void UpdateActiveTabTitle(winrt::hstring title);
Windows::Foundation::Collections::IVector<winrt::hstring> GetAllWindowLayouts();
winrt::fire_and_forget RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex);
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
TYPED_EVENT(BecameMonarch, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);

View File

@@ -22,7 +22,11 @@ namespace Microsoft.Terminal.Remoting
void RequestQuitAll();
void UpdateActiveTabTitle(String title);
Boolean DoesQuakeWindowExist();
Windows.Foundation.Collections.IVectorView<PeasantInfo> GetPeasantInfos();
void RequestMoveContent(String window, String content, UInt32 tabIndex);
event Windows.Foundation.TypedEventHandler<Object, FindTargetWindowArgs> FindTargetWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> BecameMonarch;
event Windows.Foundation.TypedEventHandler<Object, Object> WindowCreated;

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

@@ -153,10 +153,6 @@
<StaticResource x:Key="UnfocusedBorderBrush"
ResourceKey="ApplicationPageBackgroundThemeBrush" />
<StaticResource x:Key="SettingsPageBackground"
ResourceKey="SolidBackgroundFillColorTertiary" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
@@ -170,9 +166,6 @@
<StaticResource x:Key="UnfocusedBorderBrush"
ResourceKey="ApplicationPageBackgroundThemeBrush" />
<StaticResource x:Key="SettingsPageBackground"
ResourceKey="SolidBackgroundFillColorTertiary" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
@@ -190,9 +183,6 @@
-->
<StaticResource x:Key="TabViewBackground"
ResourceKey="SystemColorButtonFaceColorBrush" />
<StaticResource x:Key="SettingsPageBackground"
ResourceKey="SystemColorWindowColorBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>

View File

@@ -175,7 +175,7 @@ namespace winrt::TerminalApp::implementation
}
else if (const auto& realArgs = args.ActionArgs().try_as<MovePaneArgs>())
{
auto moved = _MovePane(realArgs.TabIndex());
auto moved = _MovePane(realArgs);
args.Handled(moved);
}
}
@@ -201,10 +201,15 @@ namespace winrt::TerminalApp::implementation
}
}
_SplitPane(realArgs.SplitDirection(),
// This is safe, we're already filtering so the value is (0, 1)
::base::saturated_cast<float>(realArgs.SplitSize()),
_MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
// _SplitPaneActiveTab(realArgs.SplitDirection(),
// // This is safe, we're already filtering so the value is (0, 1)
// ::base::saturated_cast<float>(realArgs.SplitSize()),
// _MakePane(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
_asyncSplitPaneActiveTab(realArgs.SplitDirection(),
// This is safe, we're already filtering so the value is (0, 1)
::base::saturated_cast<float>(realArgs.SplitSize()),
_prepareContentProc(realArgs.TerminalArgs(), realArgs.SplitMode() == SplitType::Duplicate));
args.Handled(true);
}
}
@@ -278,6 +283,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)
{
@@ -702,17 +756,8 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = actionArgs.ActionArgs().try_as<MoveTabArgs>())
{
auto direction = realArgs.Direction();
if (direction != MoveTabDirection::None)
{
if (auto focusedTabIndex = _GetFocusedTabIndex())
{
auto currentTabIndex = focusedTabIndex.value();
auto delta = direction == MoveTabDirection::Forward ? 1 : -1;
_TryMoveTab(currentTabIndex, currentTabIndex + delta);
}
}
actionArgs.Handled(true);
auto moved = _MoveTab(realArgs);
actionArgs.Handled(moved);
}
}
@@ -1043,4 +1088,34 @@ 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);
}
}
void TerminalPage::_HandleSwitchSelectionEndpoint(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
{
const auto handled = control.SwitchSelectionEndpoint();
args.Handled(handled);
}
}
}

View File

@@ -51,6 +51,7 @@ static const std::array settingsLoadWarningsLabels {
USES_RESOURCE(L"InvalidSplitSize"),
USES_RESOURCE(L"FailedToParseStartupActions"),
USES_RESOURCE(L"FailedToParseSubCommands"),
USES_RESOURCE(L"UnknownTheme"),
};
static const std::array settingsLoadErrorsLabels {
USES_RESOURCE(L"NoProfilesText"),
@@ -292,7 +293,7 @@ namespace winrt::TerminalApp::implementation
_root->Maximized(true);
}
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode))
if (WI_IsFlagSet(launchMode, LaunchMode::FullscreenMode) && !IsQuakeWindow())
{
_root->SetFullscreen(true);
}
@@ -367,11 +368,12 @@ namespace winrt::TerminalApp::implementation
// details here, but it does have the desired effect.
// It's not enough to set the theme on the dialog alone.
auto themingLambda{ [this](const Windows::Foundation::IInspectable& sender, const RoutedEventArgs&) {
auto theme{ _settings.GlobalSettings().Theme() };
auto theme{ _settings.GlobalSettings().CurrentTheme() };
auto requestedTheme{ theme.RequestedTheme() };
auto element{ sender.try_as<winrt::Windows::UI::Xaml::FrameworkElement>() };
while (element)
{
element.RequestedTheme(theme);
element.RequestedTheme(requestedTheme);
element = element.Parent().try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
}
} };
@@ -737,13 +739,7 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::ElementTheme AppLogic::GetRequestedTheme()
{
if (!_loadedInitialSettings)
{
// Load settings if we haven't already
LoadSettings();
}
return _settings.GlobalSettings().Theme();
return Theme().RequestedTheme();
}
bool AppLogic::GetShowTabsInTitlebar()
@@ -962,9 +958,16 @@ namespace winrt::TerminalApp::implementation
}
CATCH_LOG()
// Method Description:
// - Update the current theme of the application. This will trigger our
// RequestedThemeChanged event, to have our host change the theme of the
// root of the application.
// Arguments:
// - newTheme: The ElementTheme to apply to our elements.
void AppLogic::_RefreshThemeRoutine()
{
_ApplyTheme(_settings.GlobalSettings().Theme());
// Propagate the event to the host layer, so it can update its own UI
_RequestedThemeChangedHandlers(*this, Theme());
}
// Function Description:
@@ -1073,18 +1076,6 @@ namespace winrt::TerminalApp::implementation
return _settings;
}
// Method Description:
// - Update the current theme of the application. This will trigger our
// RequestedThemeChanged event, to have our host change the theme of the
// root of the application.
// Arguments:
// - newTheme: The ElementTheme to apply to our elements.
void AppLogic::_ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme)
{
// Propagate the event to the host layer, so it can update its own UI
_RequestedThemeChangedHandlers(*this, newTheme);
}
UIElement AppLogic::GetRoot() noexcept
{
return _root.as<winrt::Windows::UI::Xaml::Controls::Control>();
@@ -1219,6 +1210,19 @@ namespace winrt::TerminalApp::implementation
return {};
}
winrt::Windows::UI::Xaml::Media::Brush AppLogic::TitlebarBrush()
{
if (_root)
{
return _root->TitlebarBrush();
}
return { nullptr };
}
void AppLogic::WindowActivated(const bool activated)
{
_root->WindowActivated(activated);
}
bool AppLogic::HasCommandlineArguments() const noexcept
{
return _hasCommandLineArguments;
@@ -1645,4 +1649,22 @@ namespace winrt::TerminalApp::implementation
{
return _settings.GlobalSettings().ShowTitleInTitlebar();
}
Microsoft::Terminal::Settings::Model::Theme AppLogic::Theme()
{
if (!_loadedInitialSettings)
{
// Load settings if we haven't already
LoadSettings();
}
return _settings.GlobalSettings().CurrentTheme();
}
void AppLogic::AttachContent(winrt::hstring content, uint32_t tabIndex)
{
if (_root)
{
_root->AttachContent(content, tabIndex);
}
}
}

View File

@@ -117,18 +117,33 @@ namespace winrt::TerminalApp::implementation
void WindowVisibilityChanged(const bool showOrHide);
winrt::TerminalApp::TaskbarState TaskbarState();
winrt::Windows::UI::Xaml::Media::Brush TitlebarBrush();
void WindowActivated(const bool activated);
bool GetMinimizeToNotificationArea();
bool GetAlwaysShowNotificationIcon();
bool GetShowTitleInTitlebar();
void AttachContent(winrt::hstring content, uint32_t tabIndex);
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
void DismissDialog();
Windows::Foundation::Collections::IMapView<Microsoft::Terminal::Control::KeyChord, Microsoft::Terminal::Settings::Model::Command> GlobalHotkeys();
Microsoft::Terminal::Settings::Model::Theme Theme();
// -------------------------------- WinRT Events ---------------------------------
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::ElementTheme);
// PropertyChanged is surprisingly not a typed event, so we'll define that one manually.
// Usually we'd just do
// WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
//
// But what we're doing here is exposing the Page's PropertyChanged _as
// our own event_. It's a FORWARDED_CALLBACK, essentially.
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return _root->PropertyChanged(handler); }
void PropertyChanged(winrt::event_token const& token) { _root->PropertyChanged(token); }
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Settings::Model::Theme);
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
@@ -183,8 +198,6 @@ namespace winrt::TerminalApp::implementation
void _ReloadSettings();
void _OpenSettingsUI();
void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme);
bool _hasCommandLineArguments{ false };
bool _hasSettingsStartupActions{ false };
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings;
@@ -205,11 +218,14 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs, _root, RenameWindowRequested);
FORWARDED_TYPED_EVENT(IsQuakeWindowChanged, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IsQuakeWindowChanged);
FORWARDED_TYPED_EVENT(SummonWindowRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, SummonWindowRequested);
FORWARDED_TYPED_EVENT(CloseRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, CloseRequested);
FORWARDED_TYPED_EVENT(OpenSystemMenu, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, OpenSystemMenu);
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
FORWARDED_TYPED_EVENT(ShowWindowChanged, Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs, _root, ShowWindowChanged);
FORWARDED_TYPED_EVENT(RequestMoveContent, Windows::Foundation::IInspectable, winrt::TerminalApp::RequestMoveContentArgs, _root, RequestMoveContent);
#ifdef UNIT_TESTING
friend class TerminalAppLocalTests::CommandlineTest;
#endif

View File

@@ -35,7 +35,7 @@ namespace TerminalApp
// See IDialogPresenter and TerminalPage's DialogPresenter for more
// information.
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
AppLogic();
@@ -94,6 +94,8 @@ namespace TerminalApp
void WindowVisibilityChanged(Boolean showOrHide);
TaskbarState TaskbarState{ get; };
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
void WindowActivated(Boolean activated);
Boolean ShouldUsePersistedLayout();
Boolean ShouldImmediatelyHandoffToElevated();
@@ -105,7 +107,10 @@ namespace TerminalApp
Boolean GetAlwaysShowNotificationIcon();
Boolean GetShowTitleInTitlebar();
Microsoft.Terminal.Settings.Model.Theme Theme { get; };
FindTargetWindowResult FindTargetWindow(String[] args);
void AttachContent(String content, UInt32 tabIndex);
Windows.Foundation.Collections.IMapView<Microsoft.Terminal.Control.KeyChord, Microsoft.Terminal.Settings.Model.Command> GlobalHotkeys();
@@ -117,7 +122,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.ElementTheme> RequestedThemeChanged;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Theme> RequestedThemeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> ChangeMaximizeRequested;
@@ -134,5 +139,8 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, RequestMoveContentArgs> RequestMoveContent;
}
}

View File

@@ -111,7 +111,15 @@ namespace winrt::Microsoft::TerminalApp::implementation
void DebugTapConnection::_OutputHandler(const hstring str)
{
_TerminalOutputHandlers(til::visualize_control_codes(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);
}
// Called by the DebugInputTapConnection to print user input

View File

@@ -3,8 +3,6 @@
#pragma once
#include "winrt/Microsoft.UI.Xaml.Controls.h"
#include "HighlightedTextSegment.g.h"
#include "HighlightedText.g.h"

View File

@@ -119,7 +119,7 @@ Pane::Pane(std::shared_ptr<Pane> first,
// - <none>
// Return Value:
// - Arguments appropriate for a SplitPane or NewTab action
NewTerminalArgs Pane::GetTerminalArgsForPane() const
NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
{
// Leaves are the only things that have controls
assert(_IsLeaf());
@@ -164,6 +164,11 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
// object. That would work for schemes set by the Terminal, but not ones set
// by VT, but that seems good enough.
if (asContent)
{
args.ContentGuid(_control.ContentGuid());
}
return args;
}
@@ -175,14 +180,15 @@ NewTerminalArgs Pane::GetTerminalArgsForPane() const
// Arguments:
// - currentId: the id to use for the current/first pane
// - nextId: the id to use for a new pane if we split
// - asContent: TODO!
// Return Value:
// - The state from building the startup actions, includes a vector of commands,
// the original root pane, the id of the focused pane, and the number of panes
// created.
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t nextId)
Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent)
{
// if we are a leaf then all there is to do is defer to the parent.
if (_IsLeaf())
if (/*!asContent && */ _IsLeaf())
{
if (_lastActive)
{
@@ -195,16 +201,29 @@ Pane::BuildStartupState Pane::BuildStartupActions(uint32_t currentId, uint32_t n
auto buildSplitPane = [&](auto newPane) {
ActionAndArgs actionAndArgs;
actionAndArgs.Action(ShortcutAction::SplitPane);
const auto terminalArgs{ newPane->GetTerminalArgsForPane() };
const auto terminalArgs{ newPane->GetTerminalArgsForPane(asContent) };
// When creating a pane the split size is the size of the new pane
// and not position.
const auto splitDirection = _splitState == SplitState::Horizontal ? SplitDirection::Down : SplitDirection::Right;
SplitPaneArgs args{ SplitType::Manual, splitDirection, 1. - _desiredSplitPosition, terminalArgs };
// const auto splitSize = (asContent && _IsLeaf()) ? .5 : (1. - _desiredSplitPosition);
const auto splitSize = (1. - _desiredSplitPosition);
SplitPaneArgs args{ SplitType::Manual, splitDirection, splitSize, terminalArgs };
actionAndArgs.Args(args);
return actionAndArgs;
};
// if (asContent && _IsLeaf())
// {
// // TODO! This probably won't work. We probably do need to ask the parent
// // of this pane to generate the action for us. Consider moving a pane
// // that's 25% of the parent - the pane doesn't know that. Only the
// // parent does. When we recieve it, we can determine if we're putting it
// // into a tab or a pane, and then parse the NewTerminalArgs out of
// // either the splitPane or the newTab action.
// return { { buildSplitPane(shared_from_this()) }, shared_from_this(), currentId, 1 };
// }
auto buildMoveFocus = [](auto direction) {
MoveFocusArgs args{ direction };

View File

@@ -91,8 +91,8 @@ public:
std::optional<uint32_t> focusedPaneId;
uint32_t panesCreated;
};
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId);
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane() const;
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent = false);
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const;
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);

View File

@@ -158,15 +158,15 @@
<value>Windows Terminal with a preview of upcoming features</value>
</data>
<data name="ShellExtension_OpenInTerminalMenuItem_Dev" xml:space="preserve">
<value>Open in Terminal (Dev)</value>
<value>Open in Terminal (&amp;Dev)</value>
<comment>{Locked} The dev build will never be seen in multiple languages</comment>
</data>
<data name="ShellExtension_OpenInTerminalMenuItem_Preview" xml:space="preserve">
<value>Open in Terminal Preview</value>
<comment>This is a menu item that will be displayed in the Windows File Explorer that launches the Preview version of Windows Terminal</comment>
<value>Open in Terminal &amp;Preview</value>
<comment>This is a menu item that will be displayed in the Windows File Explorer that launches the Preview version of Windows Terminal. Please mark one of the characters to be an accelerator key.</comment>
</data>
<data name="ShellExtension_OpenInTerminalMenuItem" xml:space="preserve">
<value>Open in Terminal</value>
<comment>This is a menu item that will be displayed in the Windows File Explorer that launches the non-preview version of Windows Terminal</comment>
<value>Open in &amp;Terminal</value>
<comment>This is a menu item that will be displayed in the Windows File Explorer that launches the non-preview version of Windows Terminal. Please mark one of the characters to be an accelerator key.</comment>
</data>
</root>

View File

@@ -242,6 +242,10 @@
<value>&#x2022; Found a keybinding that was missing a required parameter value. This keybinding will be ignored.</value>
<comment>{Locked="&#x2022;"} This glyph is a bullet, used in a bulleted list.</comment>
</data>
<data name="UnknownTheme" xml:space="preserve">
<value>&#x2022; The specified "theme" was not found in the list of themes. Temporarily falling back to the default value.</value>
<comment>{Locked="&#x2022;"} This glyph is a bullet, used in a bulleted list.</comment>
</data>
<data name="LegacyGlobalsProperty" xml:space="preserve">
<value>The "globals" property is deprecated - your settings might need updating. </value>
<comment>{Locked="\"globals\""} </comment>

View File

@@ -44,7 +44,7 @@ namespace winrt::TerminalApp::implementation
// - <none>
// Return Value:
// - The list of actions.
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions() const
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(const bool /*asContent*/) const
{
ActionAndArgs action;
action.Action(ShortcutAction::OpenSettings);

View File

@@ -29,7 +29,7 @@ namespace winrt::TerminalApp::implementation
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const override;
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
private:
void _MakeTabViewItem() override;

View File

@@ -23,7 +23,7 @@ namespace winrt::TerminalApp::implementation
void UpdateTabViewIndex(const uint32_t idx, const uint32_t numTabs);
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions() const = 0;
virtual std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const = 0;
WINRT_CALLBACK(RequestFocusActiveControl, winrt::delegate<void()>);

View File

@@ -62,7 +62,7 @@ namespace winrt::TerminalApp::implementation
// - existingConnection: An optional connection that is already established to a PTY
// for this tab to host instead of creating one.
// If not defined, the tab will create the connection.
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs)
try
{
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
@@ -72,10 +72,10 @@ namespace winrt::TerminalApp::implementation
{
return S_FALSE;
}
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
const auto controlSettings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
// Try to handle auto-elevation
if (_maybeElevate(newTerminalArgs, settings, profile))
if (_maybeElevate(newTerminalArgs, controlSettings, profile))
{
return S_OK;
}
@@ -83,35 +83,42 @@ namespace winrt::TerminalApp::implementation
// unfortunately. This seems to be due to Centennial quirks. It works
// unpackaged, but not packaged.
//
// This call to _MakePane won't return nullptr, we already checked that
// case above with the _maybeElevate call.
_CreateNewTabFromPane(_MakePane(newTerminalArgs, false, existingConnection));
// // This call to _MakePane won't return nullptr, we already checked that
// // case above with the _maybeElevate call.
// _CreateNewTabFromPane(_MakePane(newTerminalArgs, false, nullptr));
const auto tabCount = _tabs.Size();
const auto usedManualProfile = (newTerminalArgs != nullptr) &&
(newTerminalArgs.ProfileIndex() != nullptr ||
newTerminalArgs.Profile().empty());
// TerminalSettingsCreateResult controlSettings{ nullptr };
// Profile profile{ nullptr };
// _evaluateSettings(newTerminalArgs, false /*duplicate*/, controlSettings, profile);
auto initContentProc = (newTerminalArgs && newTerminalArgs.ContentGuid() != winrt::guid{}) ?
_AttachToContentProcess(newTerminalArgs.ContentGuid()) :
_CreateNewContentProcess(profile, controlSettings);
_createNewTabFromContent(PreparedContent{ initContentProc, controlSettings, profile });
// const auto tabCount = _tabs.Size();
// const auto usedManualProfile = (newTerminalArgs != nullptr) &&
// (newTerminalArgs.ProfileIndex() != nullptr ||
// newTerminalArgs.Profile().empty());
// Lookup the name of the color scheme used by this profile.
const auto scheme = _settings.GetColorSchemeForProfile(profile);
// If they explicitly specified `null` as the scheme (indicating _no_ scheme), log
// that as the empty string.
const auto schemeName = scheme ? scheme.Name() : L"\0";
// // Lookup the name of the color scheme used by this profile.
// const auto scheme = _settings.GetColorSchemeForProfile(profile);
// // If they explicitly specified `null` as the scheme (indicating _no_ scheme), log
// // that as the empty string.
// const auto schemeName = scheme ? scheme.Name() : L"\0";
TraceLoggingWrite(
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
"TabInformation",
TraceLoggingDescription("Event emitted upon new tab creation in TerminalApp"),
TraceLoggingUInt32(1u, "EventVer", "Version of this event"),
TraceLoggingUInt32(tabCount, "TabCount", "Count of tabs currently opened in TerminalApp"),
TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"),
TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
TraceLoggingFloat64(settings.DefaultSettings().Opacity(), "TintOpacity", "Opacity preference from the settings"),
TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
// TraceLoggingWrite(
// g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
// "TabInformation",
// TraceLoggingDescription("Event emitted upon new tab creation in TerminalApp"),
// TraceLoggingUInt32(1u, "EventVer", "Version of this event"),
// TraceLoggingUInt32(tabCount, "TabCount", "Count of tabs currently opened in TerminalApp"),
// TraceLoggingBool(usedManualProfile, "ProfileSpecified", "Whether the new tab specified a profile explicitly"),
// TraceLoggingGuid(profile.Guid(), "ProfileGuid", "The GUID of the profile spawned in the new tab"),
// TraceLoggingBool(settings.DefaultSettings().UseAcrylic(), "UseAcrylic", "The acrylic preference from the settings"),
// TraceLoggingFloat64(settings.DefaultSettings().Opacity(), "TintOpacity", "Opacity preference from the settings"),
// TraceLoggingWideString(settings.DefaultSettings().FontFace().c_str(), "FontFace", "Font face chosen in the settings"),
// TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
// TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
// TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
return S_OK;
}
@@ -123,10 +130,20 @@ namespace winrt::TerminalApp::implementation
// - newTabImpl: the uninitialized tab.
void TerminalPage::_InitializeTab(winrt::com_ptr<TerminalTab> newTabImpl)
{
newTabImpl->Initialize();
// newTabImpl->Initialize();
uint32_t insertPosition = _tabs.Size();
if (_settings.GlobalSettings().NewTabPosition() == NewTabPosition::AfterCurrentTab)
{
auto currentTabIndex = _GetFocusedTabIndex();
if (currentTabIndex.has_value())
{
insertPosition = currentTabIndex.value() + 1;
}
}
// Add the new tab to the list of our tabs.
_tabs.Append(*newTabImpl);
_tabs.InsertAt(insertPosition, *newTabImpl);
_mruTabs.Append(*newTabImpl);
newTabImpl->SetDispatch(*_actionDispatch);
@@ -154,6 +171,8 @@ namespace winrt::TerminalApp::implementation
// Possibly update the icon of the tab.
page->_UpdateTabIcon(*tab);
page->_updateThemeColors();
// Update the taskbar progress as well. We'll raise our own
// SetTaskbarProgress event here, to get tell the hosting
// application to re-query this value from us.
@@ -193,7 +212,7 @@ namespace winrt::TerminalApp::implementation
if (page && tab)
{
page->_SplitTab(*tab);
page->_SplitTab(tab);
}
});
@@ -220,16 +239,20 @@ namespace winrt::TerminalApp::implementation
});
auto tabViewItem = newTabImpl->TabViewItem();
_tabView.TabItems().Append(tabViewItem);
_tabView.TabItems().InsertAt(insertPosition, tabViewItem);
// Set this tab's icon to the icon from the user's profile
if (const auto profile{ newTabImpl->GetFocusedProfile() })
{
if (!profile.Icon().empty())
{
newTabImpl->UpdateIcon(profile.Icon());
}
}
//
// TODO! This doesn't need ot live in TerminalPage like, at all. This
// should get moved inside TerminalTab::AttachRootPane, or
// TerminalTab::Initialize or something.
// if (const auto profile{ newTabImpl->GetFocusedProfile() })
// {
// if (!profile.Icon().empty())
// {
// newTabImpl->UpdateIcon(profile.Icon());
// }
// }
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabClick });
@@ -279,6 +302,41 @@ namespace winrt::TerminalApp::implementation
}
}
winrt::fire_and_forget TerminalPage::_createNewTabFromContent(PreparedContent preppedContent,
std::function<void(const winrt::com_ptr<TerminalTab>&)> postInitTab /* defaults to nullptr*/)
{
auto newTabImpl = winrt::make_self<TerminalTab>(nullptr);
// TODO! This tab should have a Content that's initialized with a blank
// grid that takes up the whole space, with the BG set to the BG color
// of the TerminalControl. So that the tab has something to show
// initially.
//
// Alternatively, the Control could be initialized with a
// AsyncAction<ContentProcess> and then when _that_ returns, the
// TermControl starts to initialize itself?
//
// That's an idea. We do already have the settings for the control, just not the content. Huh.
_InitializeTab(newTabImpl); // Adds tab to list, tabview
// If the caller requested additional setup for the tab, do that now.
// For example, DuplicateTab uses this to copy the runtime tab text from
// the old tab to the new one.
if (postInitTab)
{
postInitTab(newTabImpl);
}
// TODO! Do we need both this and the resume_background in _CreateNewContentProcess
co_await winrt::resume_background();
auto content = co_await preppedContent.initContentProc;
co_await wil::resume_foreground(Dispatcher(), CoreDispatcherPriority::High);
auto pane = _makePaneFromContent(content, preppedContent.controlSettings, preppedContent.profile);
newTabImpl->AttachRootPane(pane);
// TODO! DebugTap
}
// Method Description:
// - Get the icon of the currently focused terminal control, and set its
// tab's icon to that icon.
@@ -348,30 +406,40 @@ namespace winrt::TerminalApp::implementation
// In the future, it may be preferable to just duplicate the
// current control's live settings (which will include changes
// made through VT).
_CreateNewTabFromPane(_MakePane(nullptr, true, nullptr));
const auto runtimeTabText{ tab.GetTabText() };
if (!runtimeTabText.empty())
{
if (auto newTab{ _GetFocusedTabImpl() })
// _CreateNewTabFromPane(_MakePane(nullptr, true, nullptr));
auto initRuntimeTabTitle = [&tab](auto& newTab) {
const auto runtimeTabText{ tab.GetTabText() };
if (!runtimeTabText.empty())
{
newTab->SetTabText(runtimeTabText);
}
}
};
// TerminalSettingsCreateResult controlSettings{ nullptr };
// Profile profile{ nullptr };
// _evaluateSettings(nullptr, true, controlSettings, profile);
// auto initContentProc = _CreateNewContentProcess(profile, controlSettings);
auto preppedContent = _prepareContentProc(nullptr, true);
_createNewTabFromContent(preppedContent, initRuntimeTabTitle);
}
CATCH_LOG();
}
// Method Description:
// - Sets the specified tab as the focused tab and splits its active pane
// - Sets the specified tab as the focused tab and splits its active pane.
// This will duplicate the profile that's currently active in the given
// tab.
// Arguments:
// - tab: tab to split
void TerminalPage::_SplitTab(TerminalTab& tab)
void TerminalPage::_SplitTab(winrt::com_ptr<TerminalTab>& tab)
{
try
{
_SetFocusedTab(tab);
_SplitPane(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
_SetFocusedTab(*tab);
// _SplitPaneOnTab(tab, SplitDirection::Automatic, 0.5f, _MakePane(nullptr, true));
_asyncSplitPaneOnTab(tab, SplitDirection::Automatic, 0.5f, _prepareContentProc(nullptr, true));
}
CATCH_LOG();
}
@@ -925,6 +993,8 @@ namespace winrt::TerminalApp::implementation
_TitleChangedHandlers(*this, tab.Title());
}
_updateThemeColors();
auto tab_impl = _GetTerminalTabImpl(tab);
if (tab_impl)
{

View File

@@ -9,8 +9,11 @@
xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
Background="{ThemeResource TabViewBackground}"
mc:Ignorable="d">
<!-- GH#13143: Make sure that the Background is actually TabViewBackground here, not Transparent. This is load bearing, for showTabsInTitlebar=false. -->
<mux:TabView x:Name="TabView"
VerticalAlignment="Bottom"
HorizontalContentAlignment="Stretch"
@@ -57,7 +60,8 @@
FontSize="12">
<ToolTipService.ToolTip>
<ToolTip Placement="Mouse">
<TextBlock IsTextSelectionEnabled="False">
<TextBlock IsTextSelectionEnabled="False"
TextWrapping="Wrap">
<Run x:Uid="NewTabRun" /> <LineBreak />
<Run x:Uid="NewPaneRun"
FontStyle="Italic" /> <LineBreak />

File diff suppressed because it is too large Load Diff

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