Compare commits

..

10 Commits

Author SHA1 Message Date
Dustin L. Howett
4d00019a9b wpf: fix a handful of issues with the wpf control (#6983)
* send alt/F10 through the control
  We were not listening for WM_SYSKEY{UP,DOWN}
* extract the actual scancode during WM_CHAR, not the bitfield
  We were accidentally sending some of the additional keypress data in with
  the character event in Win32 Input Mode
* set default fg/bg to campbell
  The WPF control starts up in PowerShell blue even though it's not typically used
  in PowerShell blue.
* don't rely on the font to determine wideness
  This is a cross-port of #2928 to the WPF control
* deterministic shutdown
  In testing, I saw a handful of crashes on teardown because we were not shutting
  down the render thread properly.
* don't pass 10 for the font weight ...
  When Cascadia Code is set, it just looks silly.
* trigger render when selection is cleared, do it under lock

Fixes #6966.

(cherry picked from commit 76de2aedc2)
2020-07-20 16:14:00 -07:00
Carlos Zamora
d48ecd24f4 UIA: use full buffer comparison in rects and endpoint setter (#6447)
In UiaTextRange, `_getBufferSize` returns an optimized version of the
size of the buffer to be the origin and the last character in the
buffer. This is to improve performance on search or checking if you are
currently on the last word/line.

When setting the endpoint and drawing the bounding rectangles, we should
be retrieving the true buffer size. This is because it is still possible
to create UiaTextRanges that are outside of this optimized size. The
main source of this is `ExpandToEnclosingUnit()` when the unit is
`Document`. The end _should_ be the last visible character, but it isn't
because that would break our tests.

This is an incomplete solution. #6986 is a follow up to completely test
and implement the solution.

The crash in #6402 was caused by getting the document range (a range of
the full text buffer),  then moving the end by one character. When we
get the document range, we get the optimized size of the buffer (the
position of the last character). Moving by one character is valid
because the buffer still has more to explore. We then crash from
checking if the new position is valid on the **optimized size**, not the
**real size**.

REFERENCES

#6986 - follow up to properly handle/test this "end of buffer" problem

Closes #6402

(cherry picked from commit c390b61648)
2020-07-20 16:14:00 -07:00
Dustin L. Howett
ccf201fe44 Swap brightBlack/black in the Solarized color schemes (#6985)
Original notes from @M-Pixel:

> Console applications assume that backgrounds are black, and that
> `lightBlack`/`DarkGrey` are lighter than `black`/`Black`.  This
> assumption is accounted for by all color schemes in `defaults.json`,
> except for the Solarized themes.
>
> The Solarized Dark theme, in particular, makes `-Parameters` invisible
> against the background in PowerShell, which is obviously an unacceptable
> usability flaw.
>
> This change makes `black` and `background` to the same (which is common
> throughout the color schemes), and makes `brightBlack` (`DarkGray` in
> .NET) lighter than black (which is obviously more correct given the
> meanings of those words).

Out of the box, we ship a pretty bad behavior.

If I look at all of the existing shipped color schemes--and that
includes things like Tango and One Half--we are universally following a
`background` == `black` rule.

If I consult gnome-terminal or xterm, they do the same thing; Xterm by
default, gnome-terminal for solarized. The background generally matches
color index `0` across all their **dark** schemes. Konsole and
lxterminal disagree and map background to `0 intense` for Solarized.

I want to put our Solarized schemes on a deprecation path, but
unfortunately we still need to ship _something_ for users who we're
going to strand on them.

I'm going to have to swallow my bitter and say that yes, we should
probably just change the index mapping and go with something that works
right out of the box while we figure out how to do perceptual color
nudging and eventually remove bad defaults (like Solarized).

From #6618.

Fixes #4047.
Closes #6618.

(cherry picked from commit 04f5ee7ebf)
2020-07-20 13:51:55 -07:00
Dustin L. Howett
bcbe246a93 Update Cascadia Code to 2007.15 (#6958) 2020-07-16 18:14:57 -07:00
Dustin L. Howett
03e25f12e9 Move to the TerminalDependencies NuGet feed (#6954)
After we stood up our own NuGet feed in Azure blob storage, Azure DevOps
came out with a public artifact feed feature. I've migrated all our
packages over, and the only thing left to do is switch our project's
NuGet config to use it.

Fixes #6952
2020-07-16 17:33:23 -07:00
jtippet
7062a830b8 Smooth animation of command palette filtering (#6939)
The command palette is a ListView of commands.  As you type into the
search box, commands are added or removed from the ListView.  Currently,
each update is done by completely clearing the backing list, then adding
back any items that should be displayed.  However, this defeats the
ListView's built-in animations: upon every keystroke, ListView displays
its list-clearing animation, then animates the insertion of every item
that wasn't deleted.  This results in noticeable flickering.

This PR changes the update logic so that it updates the list using
(roughly) the minimum number of Insert and Remove calls, so the ListView
makes smoother transitions as you type.

I implemented it by keeping the existing code that builds the filtered
list, but I changed it to build into a scratch list.  Then I grafted on
a generic delta algorithm to make the real list look like the scratch
list.

To verify the delta algorithm, I tested all 360,000 permutations of
pairs of up to 5 element lists in a toy C# app.

## Validation
I'm not sure if my screen capture tool really caught all the flickering
here, but the screencasts below should give a rough idea of the
difference.  (All the flickering was becoming a nuisance while I was
testing out the HC changes.)

See the images in #6939 for more info.

Co-authored-by: Jeffrey Tippet <jtippet@microsoft.com>
2020-07-16 17:33:03 -07:00
Dan Thompson
53df6c7f96 Fix 'bcz exclusive' typo (#6938)
Without this fix, you'd end up with an empty target variable, and so
msbuild would complain and tell you to give it a target.
2020-07-16 16:58:48 -07:00
Michael Niksa
81b7e54659 Cache the viewport to make invalidation faster (#6918)
In `Renderer::TriggerRedraw`, the act of fetching the viewport from the
`pData` over and over is wasted time. We already have a cached variable
of the viewport that is updated on every scroll check (on
`TriggerScroll` and on `PaintFrame`.) Scrolling wouldn't be working
correctly if the clients weren't already notifying us that the viewport
has changed for scroll purposes, so we can just keep using that cached
value for the invalidation restriction to speed things up over fetching
it again.

## Validation Steps Performed
- Run `time cat big.txt`. Checked average time before/after, WPR traces
  before/after.

## PR Checklist
* [x] Closes perf itch
* [x] I work here
* [x] Manual test
* [x] Documentation irrelevant.
* [x] Schema irrelevant.
* [x] Am core contributor.
2020-07-16 21:46:10 +00:00
Michael Niksa
3255177dd0 Correct comment in this SPSC test as a quick follow up to merge. 2020-07-16 13:53:56 -07:00
Leonard Hecker
b62f5ea850 Added til::spsc, a lock-free, single-producer/-consumer FIFO queue (#6751)
## Summary of the Pull Request

This PR adds the `til::spsc` namespace, which implements a lock-free, single-producer, single-consumer FIFO queue ("channel"). The queue efficiently blocks the caller using Futexes if no data can be written to / read from the queue (e.g. using `WaitOnAddress` on Windows). Furthermore it allows batching of data and contains logic to signal the caller if the other side has been dropped/destructed.

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

## Detailed Description of the Pull Request / Additional comments

`til::spsc::details::arc<T>` contains most of the queue's logic and as such has the relevant documentation for its design.

## Validation Steps Performed

The queue was tested on Windows, Linux and macOS using MSVC, gcc and llvm and each of their available runtime introspection utilities in order to ensure no race conditions or memory leaks occur.
2020-07-16 20:49:06 +00:00
63 changed files with 482123 additions and 2055 deletions

25
.github/actions/spell-check/advice.txt vendored Normal file
View File

@@ -0,0 +1,25 @@
<details>
<summary>
:pencil2: Contributor please read this
</summary>
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
:warning: The command is written for posix shells. You can copy the contents of each `perl` command excluding the outer `'` marks and dropping any `'"`/`"'` quotation mark pairs into a file and then run `perl file.pl` from the root of the repository to run the code. Alternatively, you can manually insert the items...
If the listed items are:
* ... **misspelled**, then please *correct* them instead of using the command.
* ... *names*, please add them to `.github/actions/spell-check/dictionary/names.txt`.
* ... APIs, you can add them to a file in `.github/actions/spell-check/dictionary/`.
* ... just things you're using, please add them to an appropriate file in `.github/actions/spell-check/expect/`.
* ... tokens you only need in one place and shouldn't *generally be used*, you can add an item in an appropriate file in `.github/actions/spell-check/patterns/`.
See the `README.md` in each directory for more information.
:microscope: You can test your commits **without** *appending* to a PR by creating a new branch with that extra change and pushing it to your fork. The [:check-spelling](https://github.com/marketplace/actions/check-spelling) action will run in response to your **push** -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. :wink:
</details>
#### :warning: Reviewers
At present, the action that triggered this message will not show its :x: in this PR unless the branch is within this repository.
Thus, you **should** make sure that this comment has been addressed before encouraging the merge bot to merge this PR.

View File

@@ -1,6 +1,6 @@
# Allow files are lists of words to accept unconditionally
# Dictionaries are lists of words to accept unconditionally
While check spelling will complain about an expected word
While check spelling will complain about a whitelisted word
which is no longer present, you can include things here even if
they are not otherwise present in the repository.
@@ -8,14 +8,13 @@ E.g., you could include a list of system APIs here, or potential
contributors (so that if a future commit includes their name,
it'll be accepted).
## Files
### Files
| File | Description |
| ---- | ----------- |
| [Allow](allow.txt) | Supplements to the dictionary |
| [Dictionary](dictionary.txt) | Primary US English dictionary |
| [Chinese](chinese.txt) | Chinese words |
| [Japanese](japanese.txt) | Japanese words |
| [Microsoft](microsoft.txt) | Microsoft brand items |
| [Fonts](fonts.txt) | Font names |
| [Names](names.txt) | Names of people |
| [Colors](colors.txt) | Names of color |

View File

View File

@@ -0,0 +1,44 @@
ACCEPTFILES
ACCESSDENIED
alignof
bitfield
bitfields
CLASSNOTAVAILABLE
EXPCMDFLAGS
EXPCMDSTATE
fullkbd
futex
href
IAsync
IBind
IBox
IClass
IComparable
ICustom
IDialog
IDirect
IExplorer
IMap
IObject
IStorage
LCID
LSHIFT
NCHITTEST
NCLBUTTONDBLCLK
NCRBUTTONDBLCLK
NOAGGREGATION
NOREDIRECTIONBITMAP
oaidl
ocidl
PAGESCROLL
RETURNCMD
rfind
roundf
RSHIFT
rx
SIZENS
spsc
STDCPP
syscall
tmp
tx

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,8 @@
Consolas
emoji
emojis
Extralight
Gabriola
Iosevka
MDL
Monofur
Segoe
wght

View File

@@ -0,0 +1,3 @@
powf
sqrtf
isnan

View File

@@ -0,0 +1,18 @@
ACLs
altform
backplating
DACL
DACLs
LKG
mfcribbon
microsoft
microsoftonline
osgvsowi
powerrename
powershell
pscustomobject
SACLs
tdbuildteamid
vcruntime
visualstudio
wslpath

View File

@@ -1,66 +1,43 @@
Anup
austdi
arkthur
Ballmer
bhoj
Bhojwani
Bluloco
carlos
dhowett
Diviness
dsafa
duhowett
DXP
ekg
eryksun
ethanschoonover
Firefox
Gatta
glsl
Gravell
Grie
Griese
Hernan
Howett
Illhardt
iquilezles
italo
jantari
jerrysh
Kaiyu
kimwalisch
KMehrain
KODELIFE
Kodelife
Kourosh
kowalczyk
leonmsft
Lepilleur
lhecker
lukesampson
Macbook
Manandhar
masserano
mbadolato
Mehrain
menger
mgravell
michaelniksa
michkap
migrie
mikegr
mikemaccana
miloush
miniksa
niksa
nvaccess
nvda
oising
oldnewthing
opengl
osgwiki
pabhojwa
panos
paulcam
pauldotknopf
PGP
@@ -68,18 +45,11 @@ Pham
Rincewind
rprichard
Schoonover
shadertoy
Shomnipotence
simioni
Somuah
sonph
sonpham
stakx
talo
thereses
Walisch
WDX
Wellons
Wirt
Wojciech
zadjii

View File

@@ -0,0 +1,63 @@
(?:^|/)dirs$
(?:^|/)go\.mod$
(?:^|/)go\.sum$
(?:^|/)package-lock\.json$
(?:^|/)sources(?:|\.dep)$
SUMS$
\.ai$
\.bmp$
\.cer$
\.class$
\.crl$
\.crt$
\.csr$
\.dll$
\.DS_Store$
\.eot$
\.eps$
\.exe$
\.gif$
\.graffle$
\.gz$
\.icns$
\.ico$
\.jar$
\.jpeg$
\.jpg$
\.key$
\.lib$
\.lock$
\.map$
\.min\..
\.mp3$
\.mp4$
\.otf$
\.pbxproj$
\.pdf$
\.pem$
\.png$
\.psd$
\.runsettings$
\.sig$
\.so$
\.svg$
\.svgz$
\.tar$
\.tgz$
\.ttf$
\.woff
\.xcf$
\.xls
\.xpm$
\.yml$
\.zip$
^consolegit2gitfilters\.json$
^dep/
^oss/
^doc/reference/UTF8-torture-test\.txt$
^src/interactivity/onecore/BgfxEngine\.
^src/renderer/wddmcon/WddmConRenderer\.
^src/terminal/parser/ft_fuzzer/VTCommandFuzzer\.cpp$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^\.github/actions/spell-check/
^\.gitignore$

View File

@@ -1,31 +1,22 @@
AAAa
AAAAA
AAAAAAAAAAAAA
AAAAAABBBBBBCCC
AAAAABBBBBBCCC
abcd
abcd
abcde
abcdef
ABCDEFG
ABCDEFGH
ABCDEFGHIJ
abcdefghijk
ABCDEFGHIJKLMNO
abcdefghijklmnop
ABCDEFGHIJKLMNOPQRST
ABCG
abcdefghijklmnopqrstuvwxyz
ABE
abf
BBBBB
BBBBBBBB
BBBBBCCC
BBBBCCCCC
BBGGRR
EFG
EFGh
BBBBBBBBBBBBBBDDDD
QQQQQQQQQQABCDEFGHIJ
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
qrstuvwxyz
qwerty
QWERTYUIOP
qwertyuiopasdfg
YYYYYYYDDDDDDDDDDD
ZAAZZ
@@ -37,4 +28,3 @@ ZYXWVUT
ZZBBZ
ZZZBB
ZZZBZ
ZZZZZ

View File

@@ -0,0 +1,15 @@
http
td
www
ecma
rapidtables
WCAG
freedesktop
ycombinator
robertelder
kovidgoyal
leonerd
fixterms
uk
winui
appshellintegration

View File

@@ -0,0 +1,21 @@
https://(?:(?:[-a-zA-Z0-9?&=]*\.|)microsoft\.com)/[-a-zA-Z0-9?&=_#\/.]*
https://aka\.ms/[-a-zA-Z0-9?&=\/_]*
https://www\.itscj\.ipsj\.or\.jp/iso-ir/[-0-9]+\.pdf
https://www\.vt100\.net/docs/[-a-zA-Z0-9#_\/.]*
https://www.w3.org/[-a-zA-Z0-9?&=\/_#]*
https://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
https://[a-z-]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
[Pp]ublicKeyToken="?[0-9a-fA-F]{16}"?
(?:[{"]|UniqueIdentifier>)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(?:[}"]|</UniqueIdentifier)
(?:0[Xx]|\\x|U\+|#)[a-f0-9A-FGgRr]{2,}[Uu]?[Ll]{0,2}\b
microsoft/cascadia-code\@[0-9a-fA-F]{40}
\d+x\d+Logo
Scro\&ll
# selectionInput.cpp
:\\windows\\syste\b
TestUtils::VerifyExpectedString\(tb, L"[^"]+"
(?:hostSm|mach)\.ProcessString\(L"[^"]+"
\b([A-Za-z])\1{3,}\b
Base64::s_(?:En|De)code\(L"[^"]+"
VERIFY_ARE_EQUAL\(L"[^"]+"
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+/"

View File

@@ -1,15 +0,0 @@
# check-spelling/check-spelling configuration
File | Purpose | Format | Info
-|-|-|-
[allow/*.txt](allow/) | Add words to the dictionary | one word per line (only letters and `'`s allowed) | [allow](https://github.com/check-spelling/check-spelling/wiki/Configuration#allow)
[reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject)
[excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes)
[patterns/*.txt](patterns/) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns)
[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[expect/*.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect)
[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice)
Note: you can replace any of these files with a directory by the same name (minus the suffix)
and then include multiple files inside that directory (with that suffix) to merge multiple files together.

View File

@@ -1,48 +0,0 @@
<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details>
<summary>
:pencil2: Contributor please read this
</summary>
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
:warning: The command is written for posix shells. If it doesn't work for you, you can manually _add_ (one word per line) / _remove_ items to `expect.txt` and the `excludes.txt` files.
If the listed items are:
* ... **misspelled**, then please *correct* them instead of using the command.
* ... *names*, please add them to `.github/actions/spelling/allow/names.txt`.
* ... APIs, you can add them to a file in `.github/actions/spelling/allow/`.
* ... just things you're using, please add them to an appropriate file in `.github/actions/spelling/expect/`.
* ... tokens you only need in one place and shouldn't *generally be used*, you can add an item in an appropriate file in `.github/actions/spelling/patterns/`.
See the `README.md` in each directory for more information.
:microscope: You can test your commits **without** *appending* to a PR by creating a new branch with that extra change and pushing it to your fork. The [check-spelling](https://github.com/marketplace/actions/check-spelling) action will run in response to your **push** -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. :wink:
<details><summary>If the flagged items are :exploding_head: false positives</summary>
If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).
Please add a file path to the `excludes.txt` file matching the containing file.
File paths are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
../tree/HEAD/README.md) (on whichever branch you're using).
* well-formed pattern.
If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
try adding it to the `patterns.txt` file.
Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
</details>
</details>

View File

@@ -1,108 +0,0 @@
admins
allcolors
Apc
apc
breadcrumb
breadcrumbs
bsd
calt
ccmp
changelog
clickable
clig
CMMI
copyable
cybersecurity
dalet
Dcs
dcs
dialytika
dje
downside
downsides
dze
dzhe
EDDB
EDDC
Enum'd
Fitt
formattings
FTCS
ftp
fvar
gantt
gcc
geeksforgeeks
ghe
github
gje
godbolt
hostname
hostnames
https
hyperlink
hyperlinking
hyperlinks
iconify
img
inlined
It'd
kje
libfuzzer
libuv
liga
lje
Llast
llvm
Lmid
locl
lol
lorem
Lorigin
maxed
minimalistic
mkmk
mnt
mru
nje
noreply
ogonek
ok'd
overlined
pipeline
postmodern
ptys
qof
qps
rclt
reimplementation
reserialization
reserialize
reserializes
rlig
runtimes
shcha
slnt
Sos
ssh
timeline
timelines
timestamped
TLDR
tokenizes
tonos
toolset
tshe
ubuntu
uiatextrange
UIs
und
unregister
versioned
vsdevcmd
We'd
wildcards
XBox
YBox
yeru
zhe

View File

@@ -1,248 +0,0 @@
ACCEPTFILES
ACCESSDENIED
acl
aclapi
alignas
alignof
APPLYTOSUBMENUS
appxrecipe
bitfield
bitfields
BUILDBRANCH
BUILDMSG
BUILDNUMBER
BYCOMMAND
BYPOSITION
charconv
CLASSNOTAVAILABLE
CLOSEAPP
cmdletbinding
COLORPROPERTY
colspan
COMDLG
commandlinetoargv
comparand
cstdint
CXICON
CYICON
Dacl
dataobject
dcomp
DERR
dlldata
DNE
DONTADDTORECENT
DWMSBT
DWMWA
DWMWA
DWORDLONG
endfor
ENDSESSION
enumset
environstrings
EXPCMDFLAGS
EXPCMDSTATE
filetime
FILTERSPEC
FORCEFILESYSTEM
FORCEMINIMIZE
frac
fullkbd
futex
GETDESKWALLPAPER
GETHIGHCONTRAST
GETMOUSEHOVERTIME
Hashtable
HIGHCONTRASTON
HIGHCONTRASTW
hotkeys
href
hrgn
HTCLOSE
hwinsta
HWINSTA
IActivation
IApp
IAppearance
IAsync
IBind
IBox
IClass
IComparable
IComparer
IConnection
ICustom
IDialog
IDirect
IExplorer
IFACEMETHOD
IFile
IGraphics
IInheritable
IMap
IMonarch
IObject
iosfwd
IPackage
IPeasant
ISetup
isspace
IStorage
istream
IStringable
ITab
ITaskbar
itow
IUri
IVirtual
KEYSELECT
LCID
llabs
llu
localtime
lround
Lsa
lsass
LSHIFT
LTGRAY
MAINWINDOW
memchr
memicmp
MENUCOMMAND
MENUDATA
MENUINFO
MENUITEMINFOW
mmeapi
MOUSELEAVE
mov
mptt
msappx
MULTIPLEUSE
NCHITTEST
NCLBUTTONDBLCLK
NCMOUSELEAVE
NCMOUSEMOVE
NCRBUTTONDBLCLK
NIF
NIN
NOAGGREGATION
NOASYNC
NOCHANGEDIR
NOPROGRESS
NOREDIRECTIONBITMAP
NOREPEAT
NOTIFYBYPOS
NOTIFYICON
NOTIFYICONDATA
ntprivapi
oaidl
ocidl
ODR
offsetof
ofstream
onefuzz
osver
OSVERSIONINFOEXW
otms
OUTLINETEXTMETRICW
overridable
PACL
PAGESCROLL
PATINVERT
PEXPLICIT
PICKFOLDERS
pmr
ptstr
QUERYENDSESSION
rcx
REGCLS
RETURNCMD
rfind
ROOTOWNER
roundf
RSHIFT
SACL
schandle
semver
serializer
SETVERSION
SHELLEXECUTEINFOW
shobjidl
SHOWHIDE
SHOWMINIMIZED
SHOWTIP
SINGLEUSE
SIZENS
smoothstep
snprintf
spsc
sregex
SRWLOC
SRWLOCK
STDCPP
STDMETHOD
strchr
strcpy
streambuf
strtoul
Stubless
Subheader
Subpage
syscall
SYSTEMBACKDROP
TABROW
TASKBARCREATED
TBPF
THEMECHANGED
tlg
TME
tmp
tmpdir
tolower
toupper
TRACKMOUSEEVENT
TTask
TVal
UChar
UFIELD
ULARGE
UOI
UPDATEINIFILE
userenv
USEROBJECTFLAGS
Viewbox
virtualalloc
wcsstr
wcstoui
winmain
winsta
winstamin
wmemcmp
wpc
WSF
wsregex
wwinmain
xchg
XDocument
XElement
xfacet
xhash
XIcon
xiosbase
xlocale
xlocbuf
xlocinfo
xlocmes
xlocmon
xlocnum
xloctime
XMax
xmemory
XParse
xpath
xstddef
xstring
xtree
xutility
YIcon
YMax

View File

@@ -1,117 +0,0 @@
alice
aliceblue
antiquewhite
blanchedalmond
blueviolet
burlywood
cadetblue
cornflowerblue
cornsilk
cyan
darkblue
darkcyan
darkgoldenrod
darkgray
darkgreen
darkgrey
darkkhaki
darkmagenta
darkolivegreen
darkorange
darkorchid
darkred
darksalmon
darkseagreen
darkslateblue
darkslategray
darkslategrey
darkturquoise
darkviolet
deeppink
deepskyblue
dimgray
dimgrey
dodgerblue
firebrick
floralwhite
forestgreen
gainsboro
ghostwhite
greenyellow
hotpink
indian
indianred
lavenderblush
lawngreen
lemonchiffon
lightblue
lightcoral
lightcyan
lightgoldenrod
lightgoldenrodyellow
lightgray
lightgreen
lightgrey
lightpink
lightsalmon
lightseagreen
lightskyblue
lightslateblue
lightslategray
lightslategrey
lightsteelblue
lightyellow
limegreen
mediumaquamarine
mediumblue
mediumorchid
mediumpurple
mediumseagreen
mediumslateblue
mediumspringgreen
mediumturquoise
mediumvioletred
midnightblue
mintcream
mistyrose
navajo
navajowhite
navyblue
oldlace
olivedrab
orangered
palegoldenrod
palegreen
paleturquoise
palevioletred
papayawhip
peachpuff
peru
powderblue
rebecca
rebeccapurple
rosybrown
royalblue
saddlebrown
sandybrown
seagreen
sienna
skyblue
slateblue
slategray
slategrey
springgreen
steelblue
violetred
webgray
webgreen
webgrey
webmaroon
webpurple
whitesmoke
xaroon
xray
xreen
xrey
xurple
yellowgreen

View File

@@ -1,11 +0,0 @@
atan
CPrime
HBar
HPrime
isnan
LPrime
LStep
powf
RSub
sqrtf
ULP

View File

@@ -1,85 +0,0 @@
ACLs
ADMINS
advapi
altform
altforms
appendwttlogging
appx
appxbundle
appxerror
appxmanifest
ATL
backplating
bitmaps
BOMs
CPLs
cpptools
cppvsdbg
CPRs
cryptbase
DACL
DACLs
defaultlib
diffs
disposables
dotnetfeed
DTDs
DWINRT
enablewttlogging
Intelli
IVisual
libucrt
libucrtd
LKG
LOCKFILE
Lxss
mfcribbon
microsoft
microsoftonline
MSAA
msixbundle
MSVC
MSVCP
muxc
netcore
Onefuzz
osgvsowi
PFILETIME
pgc
pgo
pgosweep
powerrename
powershell
propkey
pscustomobject
QWORD
regedit
robocopy
SACLs
sdkddkver
Shobjidl
Skype
SRW
sxs
Sysinternals
sysnative
systemroot
taskkill
tasklist
tdbuildteamid
ucrt
ucrtd
unvirtualized
VCRT
vcruntime
Virtualization
visualstudio
vscode
VSTHRD
winsdkver
wlk
wslpath
wtl
wtt
wttlog
Xamarin

View File

@@ -1,523 +0,0 @@
# marker to ignore all code on line
^.*/\* #no-spell-check-line \*/.*$
# marker for ignoring a comment to the end of the line
// #no-spell-check.*$
# patch hunk comments
^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .*
# git index header
index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# cid urls
(['"])cid:.*?\g{-1}
# data url in parens
\(data:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
# data url in quotes
([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
# data url
data:[-a-zA-Z=;:/0-9+]*,\S*
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
# magnet urls
magnet:[?=:\w]+
# magnet urls
"magnet:[^"]+"
# obs:
"obs:[^"]*"
# The `\b` here means a break, it's the fancy way to handle urls, but it makes things harder to read
# In this examples content, I'm using a number of different ways to match things to show various approaches
# asciinema
\basciinema\.org/a/[0-9a-zA-Z]+
# apple
\bdeveloper\.apple\.com/[-\w?=/]+
# Apple music
\bembed\.music\.apple\.com/fr/playlist/usr-share/[-\w.]+
# appveyor api
\bci\.appveyor\.com/api/projects/status/[0-9a-z]+
# appveyor project
\bci\.appveyor\.com/project/(?:[^/\s"]*/){2}builds?/\d+/job/[0-9a-z]+
# Amazon
# Amazon
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
# AWS S3
\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]*
# AWS execute-api
\b[0-9a-z]{10}\.execute-api\.[-0-9a-z]+\.amazonaws\.com\b
# AWS ELB
\b\w+\.[-0-9a-z]+\.elb\.amazonaws\.com\b
# AWS SNS
\bsns\.[-0-9a-z]+.amazonaws\.com/[-\w/&#%_?:=]*
# AWS VPC
vpc-\w+
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
# YouTube url
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
# YouTube music
\bmusic\.youtube\.com/youtubei/v1/browse(?:[?&]\w+=[-a-zA-Z0-9?&=_]*)
# YouTube tag
<\s*youtube\s+id=['"][-a-zA-Z0-9?_]*['"]
# YouTube image
\bimg\.youtube\.com/vi/[-a-zA-Z0-9?&=_]*
# Google Accounts
\baccounts.google.com/[-_/?=.:;+%&0-9a-zA-Z]*
# Google Analytics
\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]*
# Google APIs
\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+
# Google Storage
\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|)
# Google Calendar
\bcalendar\.google\.com/calendar(?:/u/\d+|)/embed\?src=[@./?=\w&%]+
\w+\@group\.calendar\.google\.com\b
# Google DataStudio
\bdatastudio\.google\.com/(?:(?:c/|)u/\d+/|)(?:embed/|)(?:open|reporting|datasources|s)/[-0-9a-zA-Z]+(?:/page/[-0-9a-zA-Z]+|)
# The leading `/` here is as opposed to the `\b` above
# ... a short way to match `https://` or `http://` since most urls have one of those prefixes
# Google Docs
/docs\.google\.com/[a-z]+/(?:ccc\?key=\w+|(?:u/\d+|d/(?:e/|)[0-9a-zA-Z_-]+/)?(?:edit\?[-\w=#.]*|/\?[\w=&]*|))
# Google Drive
\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]*
# Google Groups
\bgroups\.google\.com/(?:(?:forum/#!|d/)(?:msg|topics?|searchin)|a)/[^/\s"]+/[-a-zA-Z0-9$]+(?:/[-a-zA-Z0-9]+)*
# Google Maps
\bmaps\.google\.com/maps\?[\w&;=]*
# Google themes
themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
# Google CDN
\bclients2\.google(?:usercontent|)\.com[-0-9a-zA-Z/.]*
# Goo.gl
/goo\.gl/[a-zA-Z0-9]+
# Google Chrome Store
\bchrome\.google\.com/webstore/detail/[-\w]*(?:/\w*|)
# Google Books
\bgoogle\.(?:\w{2,4})/books(?:/\w+)*\?[-\w\d=&#.]*
# Google Fonts
\bfonts\.(?:googleapis|gstatic)\.com/[-/?=:;+&0-9a-zA-Z]*
# Google Forms
\bforms\.gle/\w+
# Google Scholar
\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+
# Google Colab Research Drive
\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]*
# GitHub SHAs (api)
\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b
# GitHub SHAs (markdown)
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
# GitHub SHAs
\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b
# GitHub wiki
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
# githubusercontent
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
# githubassets
\bgithubassets.com/[0-9a-f]+(?:[-/\w.]+)
# gist github
\bgist\.github\.com/[^/\s"]+/[0-9a-f]+
# git.io
\bgit\.io/[0-9a-zA-Z]+
# GitHub JSON
"node_id": "[-a-zA-Z=;:/0-9+]*"
# Contributor
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
# GHSA
GHSA(?:-[0-9a-z]{4}){3}
# GitLab commit
\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b
# GitLab merge requests
\bgitlab\.[^/\s"]*/\S+/\S+/-/merge_requests/\d+/diffs#[0-9a-f]{40}\b
# GitLab uploads
\bgitlab\.[^/\s"]*/uploads/[-a-zA-Z=;:/0-9+]*
# GitLab commits
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
# binanace
accounts.binance.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
# bitbucket diff
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+
# bitbucket repositories commits
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
# bitbucket commits
\bbitbucket\.org/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
# bit.ly
\bbit\.ly/\w+
# bitrise
\bapp\.bitrise\.io/app/[0-9a-f]*/[\w.?=&]*
# bootstrapcdn.com
\bbootstrapcdn\.com/[-./\w]+
# cdn.cloudflare.com
\bcdnjs\.cloudflare\.com/[./\w]+
# circleci
\bcircleci\.com/gh(?:/[^/\s"]+){1,5}.[a-z]+\?[-0-9a-zA-Z=&]+
# gitter
\bgitter\.im(?:/[^/\s"]+){2}\?at=[0-9a-f]+
# gravatar
\bgravatar\.com/avatar/[0-9a-f]+
# ibm
[a-z.]*ibm\.com/[-_#=:%!?~.\\/\d\w]*
# imgur
\bimgur\.com/[^.]+
# Internet Archive
\barchive\.org/web/\d+/(?:[-\w.?,'/\\+&%$#_:]*)
# discord
/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,}
# Disqus
\bdisqus\.com/[-\w/%.()!?&=_]*
# medium link
\blink\.medium\.com/[a-zA-Z0-9]+
# medium
\bmedium\.com/\@?[^/\s"]+/[-\w]+
# microsoft
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
# powerbi
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
# vs devops
\bvisualstudio.com(?::443|)/[-\w/?=%&.]*
# microsoft store
\bmicrosoft\.com/store/apps/\w+
# mvnrepository.com
\bmvnrepository\.com/[-0-9a-z./]+
# now.sh
/[0-9a-z-.]+\.now\.sh\b
# oracle
\bdocs\.oracle\.com/[-0-9a-zA-Z./_?#&=]*
# chromatic.com
/\S+.chromatic.com\S*[")]
# codacy
\bapi\.codacy\.com/project/badge/Grade/[0-9a-f]+
# compai
\bcompai\.pub/v1/png/[0-9a-f]+
# mailgun api
\.api\.mailgun\.net/v3/domains/[0-9a-z]+\.mailgun.org/messages/[0-9a-zA-Z=@]*
# mailgun
\b[0-9a-z]+.mailgun.org
# /message-id/
/message-id/[-\w@./%]+
# Reddit
\breddit\.com/r/[/\w_]*
# requestb.in
\brequestb\.in/[0-9a-z]+
# sched
\b[a-z0-9]+\.sched\.com\b
# Slack url
slack://[a-zA-Z0-9?&=]+
# Slack
\bslack\.com/[-0-9a-zA-Z/_~?&=.]*
# Slack edge
\bslack-edge\.com/[-a-zA-Z0-9?&=%./]+
# Slack images
\bslack-imgs\.com/[-a-zA-Z0-9?&=%.]+
# shields.io
\bshields\.io/[-\w/%?=&.:+;,]*
# stackexchange -- https://stackexchange.com/feeds/sites
\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/)
# Sentry
[0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b
# Twitter markdown
\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\)
# Twitter hashtag
\btwitter\.com/hashtag/[\w?_=&]*
# Twitter status
\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)
# Twitter profile images
\btwimg\.com/profile_images/[_\w./]*
# Twitter media
\btwimg\.com/media/[-_\w./?=]*
# Twitter link shortened
\bt\.co/\w+
# facebook
\bfburl\.com/[0-9a-z_]+
# facebook CDN
\bfbcdn\.net/[\w/.,]*
# facebook watch
\bfb\.watch/[0-9A-Za-z]+
# dropbox
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
# ipfs protocol
ipfs://[0-9a-z]*
# ipfs url
/ipfs/[0-9a-z]*
# w3
\bw3\.org/[-0-9a-zA-Z/#.]+
# loom
\bloom\.com/embed/[0-9a-f]+
# regex101
\bregex101\.com/r/[^/\s"]+/\d+
# figma
\bfigma\.com/file(?:/[0-9a-zA-Z]+/)+
# freecodecamp.org
\bfreecodecamp\.org/[-\w/.]+
# image.tmdb.org
\bimage\.tmdb\.org/[/\w.]+
# mermaid
\bmermaid\.ink/img/[-\w]+|\bmermaid-js\.github\.io/mermaid-live-editor/#/edit/[-\w]+
# Wikipedia
\ben\.wikipedia\.org/wiki/[-\w%.#]+
# gitweb
[^"\s]+/gitweb/\S+;h=[0-9a-f]+
# HyperKitty lists
/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/
# lists
/thread\.html/[^"\s]+
# list-management
\blist-manage\.com/subscribe(?:[?&](?:u|id)=[0-9a-f]+)+
# kubectl.kubernetes.io/last-applied-configuration
"kubectl.kubernetes.io/last-applied-configuration": ".*"
# pgp
\bgnupg\.net/pks/lookup[?&=0-9a-zA-Z]*
# Spotify
\bopen\.spotify\.com/embed/playlist/\w+
# Mastodon
\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]*
# scastie
\bscastie\.scala-lang\.org/[^/]+/\w+
# images.unsplash.com
\bimages\.unsplash\.com/(?:(?:flagged|reserve)/|)[-\w./%?=%&.;]+
# pastebin
\bpastebin\.com/[\w/]+
# heroku
\b\w+\.heroku\.com/source/archive/\w+
# quip
\b\w+\.quip\.com/\w+(?:(?:#|/issues/)\w+)?
# badgen.net
\bbadgen\.net/badge/[^")\]'\s]+
# statuspage.io
\w+\.statuspage\.io\b
# media.giphy.com
\bmedia\.giphy\.com/media/[^/]+/[\w.?&=]+
# tinyurl
\btinyurl\.com/\w+
# getopts
\bgetopts\s+(?:"[^"]+"|'[^']+')
# ANSI color codes
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
# URL escaped characters
\%[0-9A-F][A-F]
# IPv6
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
# c99 hex digits (not the full format, just one I've seen)
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
# Punycode
\bxn--[-0-9a-z]+
# sha
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
# sha-... -- uses a fancy capture
(['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hex runs
\b[0-9a-fA-F]{16,}\b
# hex in url queries
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
# ssh
(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,}
# PGP
\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b
# GPG keys
\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b
# Well known gpg keys
.well-known/openpgpkey/[\w./]+
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
# integrity
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
# https://www.gnu.org/software/groff/manual/groff.html
# man troff content
\\f[BCIPR]
# '
\\\(aq
# .desktop mime types
^MimeTypes?=.*$
# .desktop localized entries
^[A-Z][a-z]+\[[a-z]+\]=.*$
# Localized .desktop content
Name\[[^\]]+\]=.*
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# crypt
"\$2[ayb]\$.{56}"
# scrypt / argon
\$(?:scrypt|argon\d+[di]*)\$\S+
# Input to GitHub JSON
content: "[-a-zA-Z=;:/0-9+]*="
# Python stringprefix / binaryprefix
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
# Regular expressions for (P|p)assword
\([A-Z]\|[a-z]\)[a-z]+
# JavaScript regular expressions
# javascript test regex
/.*/[gim]*\.test\(
# javascript match regex
\.match\(/[^/\s"]*/[gim]*\s*
# javascript match regex
\.match\(/\\[b].*?/[gim]*\s*\)(?:;|$)
# javascript regex
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
# javascript replace regex
\.replace\(/[^/\s"]*/[gim]*\s*,
# Go regular expressions
regexp?\.MustCompile\(`[^`]*`\)
# sed regular expressions
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
# go install
go install(?:\s+[a-z]+\.[-@\w/.]+)+
# kubernetes pod status lists
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
# kubectl - pods in CrashLoopBackOff
\w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+
# kubernetes object suffix
-[0-9a-f]{10}-\w{5}\s
# posthog secrets
posthog\.init\((['"])phc_[^"',]+\g{-1},
# xcode
# xcodeproject scenes
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
# xcode api botches
customObjectInstantitationMethod
# font awesome classes
\.fa-[-a-z0-9]+
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
## You could manually change `(?i)X...` to use `[Xx]...`
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
# Lorem
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
# French
# This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b
# latex
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
# the negative lookahead here is to allow catching 'templatesz' as a misspelling
# but to otherwise recognize a Windows path with \templates\foo.template or similar:
\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b
# Note that the next example is no longer necessary if you are using
# to match a string starting with a `#`, use a character-class:
[#]backwards
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# Compiler flags (Scala)
(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags
#(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (linker)
,-B
# curl arguments
\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# set arguments
\bset(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)*
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
# macOS temp folders
/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/

View File

@@ -1,117 +0,0 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes
(?:(?i)\.png$)
(?:^|/)(?i)COPYRIGHT
(?:^|/)(?i)LICEN[CS]E
(?:^|/)3rdparty/
(?:^|/)dirs$
(?:^|/)go\.mod$
(?:^|/)go\.sum$
(?:^|/)package(?:-lock|)\.json$
(?:^|/)sources(?:|\.dep)$
(?:^|/)vendor/
\.a$
\.ai$
\.avi$
\.bmp$
\.bz2$
\.cer$
\.class$
\.crl$
\.crt$
\.csr$
\.dll$
\.docx?$
\.drawio$
\.DS_Store$
\.eot$
\.eps$
\.exe$
\.gif$
\.gitattributes$
\.graffle$
\.gz$
\.icns$
\.ico$
\.jar$
\.jks$
\.jpeg$
\.jpg$
\.key$
\.lib$
\.lock$
\.map$
\.min\..
\.mod$
\.mp3$
\.mp4$
\.o$
\.ocf$
\.otf$
\.pbxproj$
\.pdf$
\.pem$
\.png$
\.psd$
\.pyc$
\.runsettings$
\.s$
\.sig$
\.so$
\.svg$
\.svgz$
\.svgz?$
\.tar$
\.tgz$
\.tiff?$
\.ttf$
\.vsdx$
\.wav$
\.webm$
\.webp$
\.woff
\.woff2?$
\.xcf$
\.xls
\.xlsx?$
\.xpm$
\.yml$
\.zip$
^\.github/actions/spelling/
^\.github/fabricbot.json$
^\.gitignore$
^\Q.git-blame-ignore-revs\E$
^\Q.github/workflows/spelling.yml\E$
^\Qdoc/reference/windows-terminal-logo.ans\E$
^\Qsamples/ConPTY/EchoCon/EchoCon/EchoCon.vcxproj.filters\E$
^\Qsrc/host/exe/Host.EXE.vcxproj.filters\E$
^\Qsrc/host/ft_host/chafa.txt\E$
^\Qsrc/tools/closetest/CloseTest.vcxproj.filters\E$
^\XamlStyler.json$
^build/config/
^consolegit2gitfilters\.json$
^dep/
^doc/reference/master-sequence-list.csv$
^doc/reference/UTF8-torture-test\.txt$
^oss/
^src/host/ft_uia/run\.bat$
^src/host/runft\.bat$
^src/host/runut\.bat$
^src/interactivity/onecore/BgfxEngine\.
^src/renderer/atlas/
^src/renderer/wddmcon/WddmConRenderer\.
^src/terminal/adapter/ut_adapter/run\.bat$
^src/terminal/parser/delfuzzpayload\.bat$
^src/terminal/parser/ft_fuzzer/run\.bat$
^src/terminal/parser/ft_fuzzer/VTCommandFuzzer\.cpp$
^src/terminal/parser/ft_fuzzwrapper/run\.bat$
^src/terminal/parser/ut_parser/Base64Test.cpp$
^src/terminal/parser/ut_parser/run\.bat$
^src/tools/integrity/packageuwp/ConsoleUWP\.appxSources$
^src/tools/lnkd/lnkd\.bat$
^src/tools/pixels/pixels\.bat$
^src/tools/texttests/fira\.txt$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^src/types/ut_types/UtilsTests.cpp$
^tools/ReleaseEngineering/ServicingPipeline.ps1$
ignore$
SUMS$

View File

@@ -1,6 +0,0 @@
WCAG
winui
appshellintegration
mdtauk
gfycat
Guake

View File

@@ -1,62 +0,0 @@
# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere
# \bm_data\b
# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test,
# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want
# to use this:
#\bfit\(
# s.b. GitHub
\bGithub\b
# s.b. GitLab
\bGitlab\b
# s.b. JavaScript
\bJavascript\b
# s.b. Microsoft
\bMicroSoft\b
# s.b. another
\ban[- ]other\b
# s.b. greater than
\bgreater then\b
# s.b. into
#\sin to\s
# s.b. opt-in
\sopt in\s
# s.b. less than
\bless then\b
# s.b. otherwise
\bother[- ]wise\b
# s.b. nonexistent
\bnon existing\b
\b[Nn]o[nt][- ]existent\b
# s.b. preexisting
[Pp]re[- ]existing
# s.b. preempt
[Pp]re[- ]empt\b
# s.b. preemptively
[Pp]re[- ]emptively
# s.b. reentrancy
[Rr]e[- ]entrancy
# s.b. reentrant
[Rr]e[- ]entrant
# s.b. workaround(s)
#\bwork[- ]arounds?\b
# Reject duplicate words
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s

View File

@@ -1,96 +0,0 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
https?://\S+
[Pp]ublicKeyToken="?[0-9a-fA-F]{16}"?
(?:[{"]|UniqueIdentifier>)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(?:[}"]|</UniqueIdentifier)
(?:0[Xx]|\\x|U\+|#)[a-f0-9A-FGgRr]{2,}[Uu]?[Ll]{0,2}\b
microsoft/cascadia-code\@[0-9a-fA-F]{40}
\d+x\d+Logo
Scro\&ll
# selectionInput.cpp
:\\windows\\syste\b
TestUtils::VerifyExpectedString\(tb, L"[^"]+"
(?:hostSm|mach)\.ProcessString\(L"[^"]+"
\b([A-Za-z])\g{-1}{3,}\b
0x[0-9A-Za-z]+
Base64::s_(?:En|De)code\(L"[^"]+"
VERIFY_ARE_EQUAL\(L"[^"]+"
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+/"
std::memory_order_[\w]+
D2DERR_SHADER_COMPILE_FAILED
TIL_FEATURE_[0-9A-Z_]+
vcvars\w*
ROY\sG\.\sBIV
!(?:(?i)ESC)!\[
!(?:(?i)CSI)!(?:\d+(?:;\d+|)m|[ABCDF])
# Python stringprefix / binaryprefix
\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'
# Automatically suggested patterns
# hit-count: 3831 file-count: 582
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# hit-count: 71 file-count: 35
# Compiler flags
(?:^|[\t ,"'`=(])-[D](?=[A-Z]{2,}|[A-Z][a-z])
(?:^|[\t ,"'`=(])-[X](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# hit-count: 41 file-count: 28
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# hit-count: 20 file-count: 9
# hex runs
\b[0-9a-fA-F]{16,}\b
# hit-count: 10 file-count: 7
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hit-count: 4 file-count: 4
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
# hit-count: 4 file-count: 1
# ANSI color codes
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
# hit-count: 2 file-count: 1
# latex
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
# hit-count: 1 file-count: 1
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
# hit-count: 1 file-count: 1
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
# hit-count: 1 file-count: 1
# French
# This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b
# acceptable duplicates
# ls directory listings
[-bcdlpsw](?:[-r][-w][-sx]){3}\s+\d+\s+(\S+)\s+\g{-1}\s+\d+\s+
# C/idl types + English ...
\s(Guid|long|LONG|that) \g{-1}\s
# javadoc / .net
(?:[\\@](?:groupname|param)|(?:public|private)(?:\s+static|\s+readonly)*)\s+(\w+)\s+\g{-1}\s
# Commit message -- Signed-off-by and friends
^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$
# Autogenerated revert commit message
^This reverts commit [0-9a-f]{40}\.$
# vtmode
--vtmode\s+(\w+)\s+\g{-1}\s
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b

View File

@@ -1,12 +0,0 @@
^attache$
^attacher$
^attachers$
benefitting
occurences?
^dependan.*
^oer$
Sorce
^[Ss]pae.*
^untill$
^untilling$
^wether.*

20
.github/workflows/spelling.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Spell checking
on:
push:
schedule:
# * is a special character in YAML so you have to quote this string
- cron: '15 * * * *'
jobs:
build:
name: Spell checking
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.0.0
with:
fetch-depth: 5
- uses: check-spelling/check-spelling@0.0.16-alpha
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
bucket: .github/actions
project: spell-check

View File

@@ -1,134 +0,0 @@
# spelling.yml is blocked per https://github.com/check-spelling/check-spelling/security/advisories/GHSA-g86g-chm8-7r2p
name: Spell checking
# Comment management is handled through a secondary job, for details see:
# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions
#
# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment
# (in odd cases, it might actually run just to collapse a commment, but that's fairly rare)
# it needs `contents: write` in order to add a comment.
#
# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment
# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment)
# it needs `pull-requests: write` in order to manipulate those comments.
# Updating pull request branches is managed via comment handling.
# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list
#
# These elements work together to make it happen:
#
# `on.issue_comment`
# This event listens to comments by users asking to update the metadata.
#
# `jobs.update`
# This job runs in response to an issue_comment and will push a new commit
# to update the spelling metadata.
#
# `with.experimental_apply_changes_via_bot`
# Tells the action to support and generate messages that enable it
# to make a commit to update the spelling metadata.
#
# `with.ssh_key`
# In order to trigger workflows when the commit is made, you can provide a
# secret (typically, a write-enabled github deploy key).
#
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
on:
push:
branches:
- "**"
tags-ignore:
- "**"
pull_request_target:
branches:
- "**"
tags-ignore:
- "**"
types:
- 'opened'
- 'reopened'
- 'synchronize'
issue_comment:
types:
- 'created'
jobs:
spelling:
name: Spell checking
permissions:
contents: read
pull-requests: read
actions: read
outputs:
followup: ${{ steps.spelling.outputs.followup }}
runs-on: ubuntu-latest
if: "contains(github.event_name, 'pull_request') || github.event_name == 'push'"
concurrency:
group: spelling-${{ github.event.pull_request.number || github.ref }}
# note: If you use only_check_changed_files, you do not want cancel-in-progress
cancel-in-progress: true
steps:
- name: check-spelling
id: spelling
uses: check-spelling/check-spelling@v0.0.21
with:
suppress_push_for_open_pull_request: 1
checkout: true
check_file_names: 1
spell_check_this: check-spelling/spell-check-this@prerelease
post_comment: 0
use_magic_file: 1
extra_dictionary_limit: 10
extra_dictionaries:
cspell:software-terms/src/software-terms.txt
cspell:python/src/python/python-lib.txt
cspell:node/node.txt
cspell:cpp/src/stdlib-c.txt
cspell:cpp/src/stdlib-cpp.txt
cspell:fullstack/fullstack.txt
cspell:filetypes/filetypes.txt
cspell:html/html.txt
cspell:cpp/src/compiler-msvc.txt
cspell:python/src/common/extra.txt
cspell:powershell/powershell.txt
cspell:aws/aws.txt
cspell:cpp/src/lang-keywords.txt
cspell:npm/npm.txt
cspell:dotnet/dotnet.txt
cspell:python/src/python/python.txt
cspell:css/css.txt
cspell:cpp/src/stdlib-cmath.txt
check_extra_dictionaries: ''
comment-push:
name: Report (Push)
# If your workflow isn't running on push, you can remove this job
runs-on: ubuntu-latest
needs: spelling
permissions:
contents: write
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.21
with:
checkout: true
spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }}
comment-pr:
name: Report (PR)
# If you workflow isn't running on pull_request*, you can remove this job
runs-on: ubuntu-latest
needs: spelling
permissions:
pull-requests: write
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.21
with:
checkout: true
spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }}

View File

@@ -8,7 +8,7 @@
<!--<add key="Static Package Dependencies" value="dep\packages" />-->
<!-- Use our own NuGet Feed -->
<add key="Windows Terminal NuGet Feed" value="https://terminalnuget.blob.core.windows.net/feed/index.json" />
<add key="TerminalDependencies" value="https://pkgs.dev.azure.com/ms/terminal/_packaging/TerminalDependencies/nuget/v3/index.json" />
<!-- Internal NuGet feeds that may not be accessible outside Microsoft corporate network -->
<!--<add key="TAEF - internal" value="https://microsoft.pkgs.visualstudio.com/DefaultCollection/_packaging/Taef/nuget/v3/index.json" />

Binary file not shown.

Binary file not shown.

View File

@@ -17,5 +17,5 @@ Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadi
### Fonts Included
* Cascadia Code, Cascadia Mono (2007.01)
* from microsoft/cascadia-code@311cc603f30635da704b6a7d13050e245e61667b
* Cascadia Code, Cascadia Mono (2007.15)
* from microsoft/cascadia-code@2a54363b2c867f7ae811b9a034c0024cef67de96

View File

@@ -24,6 +24,25 @@ static constexpr bool _IsMouseMessage(UINT uMsg)
uMsg == WM_MOUSEMOVE || uMsg == WM_MOUSEWHEEL;
}
// Helper static function to ensure that all ambiguous-width glyphs are reported as narrow.
// See microsoft/terminal#2066 for more info.
static bool _IsGlyphWideForceNarrowFallback(const std::wstring_view /* glyph */) noexcept
{
return false; // glyph is not wide.
}
static bool _EnsureStaticInitialization()
{
// use C++11 magic statics to make sure we only do this once.
static bool initialized = []() {
// *** THIS IS A SINGLETON ***
SetGlyphWidthFallback(_IsGlyphWideForceNarrowFallback);
return true;
}();
return initialized;
}
LRESULT CALLBACK HwndTerminal::HwndTerminalWndProc(
HWND hwnd,
UINT uMsg,
@@ -72,7 +91,7 @@ try
{
const auto bufferData = terminal->_terminal->RetrieveSelectedTextFromBuffer(false);
LOG_IF_FAILED(terminal->_CopyTextToSystemClipboard(bufferData, true));
terminal->_terminal->ClearSelection();
TerminalClearSelection(terminal);
}
CATCH_LOG();
}
@@ -81,6 +100,11 @@ try
terminal->_PasteTextFromClipboard();
}
return 0;
case WM_DESTROY:
// Release Terminal's hwnd so Teardown doesn't try to destroy it again
terminal->_hwnd.release();
terminal->Teardown();
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
@@ -114,14 +138,16 @@ static bool RegisterTermClass(HINSTANCE hInstance) noexcept
}
HwndTerminal::HwndTerminal(HWND parentHwnd) :
_desiredFont{ L"Consolas", 0, 10, { 0, 14 }, CP_UTF8 },
_actualFont{ L"Consolas", 0, 10, { 0, 14 }, CP_UTF8, false },
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8 },
_actualFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8, false },
_uiaProvider{ nullptr },
_uiaProviderInitialized{ false },
_currentDpi{ USER_DEFAULT_SCREEN_DPI },
_pfnWriteCallback{ nullptr },
_multiClickTime{ 500 } // this will be overwritten by the windows system double-click time
{
_EnsureStaticInitialization();
HINSTANCE hInstance = wil::GetModuleInstanceHandle();
if (RegisterTermClass(hInstance))
@@ -148,6 +174,11 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
}
}
HwndTerminal::~HwndTerminal()
{
Teardown();
}
HRESULT HwndTerminal::Initialize()
{
_terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>();
@@ -162,9 +193,6 @@ HRESULT HwndTerminal::Initialize()
RETURN_IF_FAILED(dxEngine->Enable());
_renderer->AddRenderEngine(dxEngine.get());
const auto pfn = std::bind(&::Microsoft::Console::Render::Renderer::IsGlyphWideByFont, _renderer.get(), std::placeholders::_1);
SetGlyphWidthFallback(pfn);
_UpdateFont(USER_DEFAULT_SCREEN_DPI);
RECT windowRect;
GetWindowRect(_hwnd.get(), &windowRect);
@@ -181,8 +209,8 @@ HRESULT HwndTerminal::Initialize()
_terminal->SetBackgroundCallback([](auto) {});
_terminal->Create(COORD{ 80, 25 }, 1000, *_renderer);
_terminal->SetDefaultBackground(RGB(5, 27, 80));
_terminal->SetDefaultForeground(RGB(255, 255, 255));
_terminal->SetDefaultBackground(RGB(12, 12, 12));
_terminal->SetDefaultForeground(RGB(204, 204, 204));
_terminal->SetWriteInputCallback([=](std::wstring & input) noexcept { _WriteTextToConnection(input); });
localPointerToThread->EnablePainting();
@@ -191,6 +219,33 @@ HRESULT HwndTerminal::Initialize()
return S_OK;
}
void HwndTerminal::Teardown() noexcept
try
{
// As a rule, detach resources from the Terminal before shutting them down.
// This ensures that teardown is reentrant.
// Shut down the renderer (and therefore the thread) before we implode
if (auto localRenderEngine{ std::exchange(_renderEngine, nullptr) })
{
if (auto localRenderer{ std::exchange(_renderer, nullptr) })
{
localRenderer->TriggerTeardown();
// renderer is destroyed
}
// renderEngine is destroyed
}
if (auto localHwnd{ _hwnd.release() })
{
// If we're being called through WM_DESTROY, we won't get here (hwnd is already released)
// If we're not, we may end up in Teardown _again_... but by the time we do, all other
// resources have been released and will not be released again.
DestroyWindow(localHwnd);
}
}
CATCH_LOG();
void HwndTerminal::RegisterScrollCallback(std::function<void(int, int, int)> callback)
{
_terminal->SetScrollPositionChangedCallback(callback);
@@ -467,11 +522,21 @@ try
}
CATCH_RETURN();
void HwndTerminal::_ClearSelection() noexcept
try
{
auto lock{ _terminal->LockForWriting() };
_terminal->ClearSelection();
_renderer->TriggerSelection();
}
CATCH_LOG();
void _stdcall TerminalClearSelection(void* terminal)
{
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
publicTerminal->_terminal->ClearSelection();
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
publicTerminal->_ClearSelection();
}
bool _stdcall TerminalIsSelectionActive(void* terminal)
{
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
@@ -482,9 +547,10 @@ bool _stdcall TerminalIsSelectionActive(void* terminal)
// Returns the selected text in the terminal.
const wchar_t* _stdcall TerminalGetSelection(void* terminal)
{
const auto publicTerminal = static_cast<const HwndTerminal*>(terminal);
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
const auto bufferData = publicTerminal->_terminal->RetrieveSelectedTextFromBuffer(false);
publicTerminal->_ClearSelection();
// convert text: vector<string> --> string
std::wstring selectedText;
@@ -494,8 +560,6 @@ const wchar_t* _stdcall TerminalGetSelection(void* terminal)
}
auto returnText = wil::make_cotaskmem_string_nothrow(selectedText.c_str());
TerminalClearSelection(terminal);
return returnText.release();
}
@@ -574,7 +638,7 @@ try
{
if (_terminal->IsSelectionActive())
{
_terminal->ClearSelection();
_ClearSelection();
if (ch == UNICODE_ESC)
{
// ESC should clear any selection before it triggers input.
@@ -632,7 +696,7 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
publicTerminal->_terminal->SetCursorStyle(theme.CursorStyle);
publicTerminal->_desiredFont = { fontFamily, 0, 10, { 0, fontSize }, CP_UTF8 };
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, { 0, fontSize }, CP_UTF8 };
publicTerminal->_UpdateFont(newDpi);
// When the font changes the terminal dimensions need to be recalculated since the available row and column

View File

@@ -51,9 +51,10 @@ public:
HwndTerminal(HwndTerminal&&) = default;
HwndTerminal& operator=(const HwndTerminal&) = default;
HwndTerminal& operator=(HwndTerminal&&) = default;
~HwndTerminal() = default;
~HwndTerminal();
HRESULT Initialize();
void Teardown() noexcept;
void SendOutput(std::wstring_view data);
HRESULT Refresh(const SIZE windowSize, _Out_ COORD* dimensions);
void RegisterScrollCallback(std::function<void(int, int, int)> callback);
@@ -112,6 +113,8 @@ private:
HRESULT _MoveSelection(LPARAM lParam) noexcept;
IRawElementProviderSimple* _GetUiaProvider() noexcept;
void _ClearSelection() noexcept;
bool _CanSendVTMouseInput() const noexcept;
bool _SendMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam) noexcept;

View File

@@ -271,16 +271,17 @@ namespace winrt::TerminalApp::implementation
};
// Method Description:
// - Update our list of filtered actions to reflect the current contents of
// - Produce a list of filtered actions to reflect the current contents of
// the input box. For more details on which commands will be displayed,
// see `_getWeight`.
// Arguments:
// - <none>
// - A collection that will receive the filtered actions
// Return Value:
// - <none>
void CommandPalette::_updateFilteredActions()
std::vector<winrt::TerminalApp::Command> CommandPalette::_collectFilteredActions()
{
_filteredActions.Clear();
std::vector<winrt::TerminalApp::Command> actions;
auto searchText = _searchBox().Text();
const bool addAll = searchText.empty();
@@ -303,10 +304,10 @@ namespace winrt::TerminalApp::implementation
for (auto action : sortedCommands)
{
_filteredActions.Append(action);
actions.push_back(action);
}
return;
return actions;
}
// Here, there was some filter text.
@@ -343,7 +344,56 @@ namespace winrt::TerminalApp::implementation
{
auto top = heap.top();
heap.pop();
_filteredActions.Append(top.command);
actions.push_back(top.command);
}
return actions;
}
// Method Description:
// - Update our list of filtered actions to reflect the current contents of
// the input box. For more details on which commands will be displayed,
// see `_getWeight`.
// Arguments:
// - <none>
// Return Value:
// - <none>
void CommandPalette::_updateFilteredActions()
{
auto actions = _collectFilteredActions();
// Make _filteredActions look identical to actions, using only Insert and Remove.
// This allows WinUI to nicely animate the ListView as it changes.
for (uint32_t i = 0; i < _filteredActions.Size() && i < actions.size(); i++)
{
for (uint32_t j = i; j < _filteredActions.Size(); j++)
{
if (_filteredActions.GetAt(j) == actions[i])
{
for (uint32_t k = i; k < j; k++)
{
_filteredActions.RemoveAt(i);
}
break;
}
}
if (_filteredActions.GetAt(i) != actions[i])
{
_filteredActions.InsertAt(i, actions[i]);
}
}
// Remove any extra trailing items from the destination
while (_filteredActions.Size() > actions.size())
{
_filteredActions.RemoveAtEnd();
}
// Add any extra trailing items from the source
while (_filteredActions.Size() < actions.size())
{
_filteredActions.Append(actions[_filteredActions.Size()]);
}
}

View File

@@ -37,6 +37,7 @@ namespace winrt::TerminalApp::implementation
void _selectNextItem(const bool moveDown);
void _updateFilteredActions();
std::vector<winrt::TerminalApp::Command> _collectFilteredActions();
static int _getWeight(const winrt::hstring& searchText, const winrt::hstring& name);
void _close();

View File

@@ -187,7 +187,7 @@
"foreground": "#839496",
"background": "#002B36",
"cursorColor": "#FFFFFF",
"black": "#073642",
"black": "#002B36",
"red": "#DC322F",
"green": "#859900",
"yellow": "#B58900",
@@ -195,7 +195,7 @@
"purple": "#D33682",
"cyan": "#2AA198",
"white": "#EEE8D5",
"brightBlack": "#002B36",
"brightBlack": "#073642",
"brightRed": "#CB4B16",
"brightGreen": "#586E75",
"brightYellow": "#657B83",
@@ -209,7 +209,7 @@
"foreground": "#657B83",
"background": "#FDF6E3",
"cursorColor": "#002B36",
"black": "#073642",
"black": "#002B36",
"red": "#DC322F",
"green": "#859900",
"yellow": "#B58900",
@@ -217,7 +217,7 @@
"purple": "#D33682",
"cyan": "#2AA198",
"white": "#EEE8D5",
"brightBlack": "#002B36",
"brightBlack": "#073642",
"brightRed": "#CB4B16",
"brightGreen": "#586E75",
"brightYellow": "#657B83",

View File

@@ -554,21 +554,21 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// This event is only registered during terminal initialization,
// so we don't need to check _initializedTerminal.
// We also don't lock for things that come back from the renderer.
auto chainHandle = _renderEngine->GetSwapChainHandle();
auto chain = _renderEngine->GetSwapChain();
auto weakThis{ get_weak() };
co_await winrt::resume_foreground(Dispatcher());
if (auto control{ weakThis.get() })
{
_AttachDxgiSwapChainToXaml(chainHandle);
_AttachDxgiSwapChainToXaml(chain.Get());
}
}
void TermControl::_AttachDxgiSwapChainToXaml(HANDLE swapChainHandle)
void TermControl::_AttachDxgiSwapChainToXaml(IDXGISwapChain1* swapChain)
{
auto nativePanel = SwapChainPanel().as<ISwapChainPanelNative2>();
nativePanel->SetSwapChainHandle(swapChainHandle);
auto nativePanel = SwapChainPanel().as<ISwapChainPanelNative>();
nativePanel->SetSwapChain(swapChain);
}
bool TermControl::_InitializeTerminal()
@@ -672,7 +672,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
THROW_IF_FAILED(dxEngine->Enable());
_renderEngine = std::move(dxEngine);
_AttachDxgiSwapChainToXaml(_renderEngine->GetSwapChainHandle());
_AttachDxgiSwapChainToXaml(_renderEngine->GetSwapChain().Get());
// Tell the DX Engine to notify us when the swap chain changes.
// We do this after we initially set the swapchain so as to avoid unnecessary callbacks (and locking problems)

View File

@@ -81,7 +81,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
void ToggleRetroEffect();
winrt::fire_and_forget RenderEngineSwapChainChanged();
void _AttachDxgiSwapChainToXaml(HANDLE swapChainHandle);
void _AttachDxgiSwapChainToXaml(IDXGISwapChain1* swapChain);
winrt::fire_and_forget _RendererEnteredErrorState();
void _RenderRetryButton_Click(IInspectable const& button, IInspectable const& args);

View File

@@ -62,6 +62,16 @@ namespace Microsoft.Terminal.Wpf
/// </summary>
WM_CHAR = 0x0102,
/// <summary>
/// The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when a system key is pressed. A system key is F10 or Alt+Something.
/// </summary>
WM_SYSKEYDOWN = 0x0104,
/// <summary>
/// The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when a system key is released. A system key is F10 or Alt+Something.
/// </summary>
WM_SYSKEYUP = 0x0105,
/// <summary>
/// The WM_MOUSEMOVE message is posted to a window when the cursor moves. If the mouse is not captured, the message is posted to the window that contains the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>

View File

@@ -235,6 +235,7 @@ namespace Microsoft.Terminal.Wpf
this.Focus();
NativeMethods.SetFocus(this.hwnd);
break;
case NativeMethods.WindowMessage.WM_SYSKEYDOWN: // fallthrough
case NativeMethods.WindowMessage.WM_KEYDOWN:
{
// WM_KEYDOWN lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keydown
@@ -246,6 +247,7 @@ namespace Microsoft.Terminal.Wpf
break;
}
case NativeMethods.WindowMessage.WM_SYSKEYUP: // fallthrough
case NativeMethods.WindowMessage.WM_KEYUP:
{
// WM_KEYUP lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keyup
@@ -255,9 +257,13 @@ namespace Microsoft.Terminal.Wpf
}
case NativeMethods.WindowMessage.WM_CHAR:
// WM_CHAR lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-char
NativeMethods.TerminalSendCharEvent(this.terminal, (char)wParam, (ushort)((uint)lParam >> 16));
break;
{
// WM_CHAR lParam layout documentation: https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-char
ulong scanCode = (((ulong)lParam) & 0x00FF0000) >> 16;
NativeMethods.TerminalSendCharEvent(this.terminal, (char)wParam, (ushort)scanCode);
break;
}
case NativeMethods.WindowMessage.WM_WINDOWPOSCHANGED:
var windowpos = (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(NativeMethods.WINDOWPOS));
if (((NativeMethods.SetWindowPosFlags)windowpos.flags).HasFlag(NativeMethods.SetWindowPosFlags.SWP_NOSIZE))

View File

@@ -13,7 +13,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>onecoreuap_apiset.lib;d3dcompiler.lib;dwmapi.lib;uxtheme.lib;shlwapi.lib;ntdll.lib;dcomp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>onecoreuap_apiset.lib;d3dcompiler.lib;dwmapi.lib;uxtheme.lib;shlwapi.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>

View File

@@ -254,6 +254,145 @@ void VtIoTests::DtorTestStackAllocMany()
}
}
class MockRenderData : public IRenderData, IUiaData
{
public:
Microsoft::Console::Types::Viewport GetViewport() noexcept override
{
return Microsoft::Console::Types::Viewport{};
}
COORD GetTextBufferEndPosition() const noexcept override
{
return COORD{};
}
const TextBuffer& GetTextBuffer() noexcept override
{
FAIL_FAST_HR(E_NOTIMPL);
}
const FontInfo& GetFontInfo() noexcept override
{
FAIL_FAST_HR(E_NOTIMPL);
}
std::vector<Microsoft::Console::Types::Viewport> GetSelectionRects() noexcept override
{
return std::vector<Microsoft::Console::Types::Viewport>{};
}
void LockConsole() noexcept override
{
}
void UnlockConsole() noexcept override
{
}
const TextAttribute GetDefaultBrushColors() noexcept override
{
return TextAttribute{};
}
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& /*attr*/) const noexcept override
{
return std::make_pair(COLORREF{}, COLORREF{});
}
COORD GetCursorPosition() const noexcept override
{
return COORD{};
}
bool IsCursorVisible() const noexcept override
{
return false;
}
bool IsCursorOn() const noexcept override
{
return false;
}
ULONG GetCursorHeight() const noexcept override
{
return 42ul;
}
CursorType GetCursorStyle() const noexcept override
{
return CursorType::FullBox;
}
ULONG GetCursorPixelWidth() const noexcept override
{
return 12ul;
}
COLORREF GetCursorColor() const noexcept override
{
return COLORREF{};
}
bool IsCursorDoubleWidth() const override
{
return false;
}
bool IsScreenReversed() const noexcept override
{
return false;
}
const std::vector<RenderOverlay> GetOverlays() const noexcept override
{
return std::vector<RenderOverlay>{};
}
const bool IsGridLineDrawingAllowed() noexcept override
{
return false;
}
const std::wstring GetConsoleTitle() const noexcept override
{
return std::wstring{};
}
const bool IsSelectionActive() const override
{
return false;
}
const bool IsBlockSelection() const noexcept override
{
return false;
}
void ClearSelection() override
{
}
void SelectNewRegion(const COORD /*coordStart*/, const COORD /*coordEnd*/) override
{
}
const COORD GetSelectionAnchor() const noexcept
{
return COORD{};
}
const COORD GetSelectionEnd() const noexcept
{
return COORD{};
}
void ColorSelection(const COORD /*coordSelectionStart*/, const COORD /*coordSelectionEnd*/, const TextAttribute /*attr*/)
{
}
};
void VtIoTests::RendererDtorAndThread()
{
Log::Comment(NoThrowString().Format(
@@ -261,9 +400,10 @@ void VtIoTests::RendererDtorAndThread()
for (int i = 0; i < 16; ++i)
{
auto data = std::make_unique<MockRenderData>();
auto thread = std::make_unique<Microsoft::Console::Render::RenderThread>();
auto* pThread = thread.get();
auto pRenderer = std::make_unique<Microsoft::Console::Render::Renderer>(nullptr, nullptr, 0, std::move(thread));
auto pRenderer = std::make_unique<Microsoft::Console::Render::Renderer>(data.get(), nullptr, 0, std::move(thread));
VERIFY_SUCCEEDED(pThread->Initialize(pRenderer.get()));
// Sleep for a hot sec to make sure the thread starts before we enable painting
// If you don't, the thread might wait on the paint enabled event AFTER
@@ -286,9 +426,10 @@ void VtIoTests::RendererDtorAndThreadAndDx()
for (int i = 0; i < 16; ++i)
{
auto data = std::make_unique<MockRenderData>();
auto thread = std::make_unique<Microsoft::Console::Render::RenderThread>();
auto* pThread = thread.get();
auto pRenderer = std::make_unique<Microsoft::Console::Render::Renderer>(nullptr, nullptr, 0, std::move(thread));
auto pRenderer = std::make_unique<Microsoft::Console::Render::Renderer>(data.get(), nullptr, 0, std::move(thread));
VERIFY_SUCCEEDED(pThread->Initialize(pRenderer.get()));
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();

View File

@@ -15,6 +15,7 @@
#include "til/rectangle.h"
#include "til/bitmap.h"
#include "til/u8u16convert.h"
#include "til/spsc.h"
namespace til // Terminal Implementation Library. Also: "Today I Learned"
{

643
src/inc/til/spsc.h Normal file
View File

@@ -0,0 +1,643 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
// til::spsc::details::arc requires std::atomic<size_type>::wait() and ::notify_one() and at the time of writing no
// STL supports these. Since both Windows and Linux offer a Futex implementation we can easily implement this though.
// On other platforms we fall back to using a std::condition_variable.
#if __cpp_lib_atomic_wait >= 201907
#define _TIL_SPSC_DETAIL_POSITION_IMPL_NATIVE 1
#elif defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_WIN8
#define _TIL_SPSC_DETAIL_POSITION_IMPL_WIN 1
#elif __linux__
#define _TIL_SPSC_DETAIL_POSITION_IMPL_LINUX 1
#else
#define _TIL_SPSC_DETAIL_POSITION_IMPL_FALLBACK 1
#endif
// til: Terminal Implementation Library. Also: "Today I Learned".
// spsc: Single Producer Single Consumer. A SPSC queue/channel sends data from exactly one sender to one receiver.
namespace til::spsc
{
using size_type = uint32_t;
namespace details
{
static constexpr size_type position_mask = std::numeric_limits<size_type>::max() >> 2u; // 0b00111....
static constexpr size_type revolution_flag = 1u << (std::numeric_limits<size_type>::digits - 2u); // 0b01000....
static constexpr size_type drop_flag = 1u << (std::numeric_limits<size_type>::digits - 1u); // 0b10000....
struct block_initially_policy
{
using _spsc_policy = int;
static constexpr bool _block_forever = false;
};
struct block_forever_policy
{
using _spsc_policy = int;
static constexpr bool _block_forever = true;
};
template<typename WaitPolicy>
using enable_if_wait_policy_t = typename std::remove_reference_t<WaitPolicy>::_spsc_policy;
#if _TIL_SPSC_DETAIL_POSITION_IMPL_NATIVE
using atomic_size_type = std::atomic<size_type>;
#else
// atomic_size_type is a fallback if native std::atomic<size_type>::wait()
// and ::notify_one() methods are unavailable in the STL.
struct atomic_size_type
{
size_type load(std::memory_order order) const noexcept
{
return _value.load(order);
}
void store(size_type desired, std::memory_order order) noexcept
{
#if _TIL_SPSC_DETAIL_POSITION_IMPL_FALLBACK
// We must use a lock here to prevent us from modifying the value
// in between wait() reading the value and the thread being suspended.
std::lock_guard<std::mutex> lock{ _m };
#endif
_value.store(desired, order);
}
void wait(size_type old, [[maybe_unused]] std::memory_order order) const noexcept
{
#if _TIL_SPSC_DETAIL_POSITION_IMPL_WIN
#pragma warning(suppress : 26492) // Don't use const_cast to cast away const or volatile
WaitOnAddress(const_cast<std::atomic<size_type>*>(&_value), &old, sizeof(_value), INFINITE);
#elif _TIL_SPSC_DETAIL_POSITION_IMPL_LINUX
futex(FUTEX_WAIT_PRIVATE, old);
#elif _TIL_SPSC_DETAIL_POSITION_IMPL_FALLBACK
std::unique_lock<std::mutex> lock{ _m };
_cv.wait(lock, [&]() { return _value.load(order) != old; });
#endif
}
void notify_one() noexcept
{
#if _TIL_SPSC_DETAIL_POSITION_IMPL_WIN
WakeByAddressSingle(&_value);
#elif _TIL_SPSC_DETAIL_POSITION_IMPL_LINUX
futex(FUTEX_WAKE_PRIVATE, 1);
#elif _TIL_SPSC_DETAIL_POSITION_IMPL_FALLBACK
_cv.notify_one();
#endif
}
private:
#if _TIL_SPSC_DETAIL_POSITION_IMPL_LINUX
inline void futex(int futex_op, size_type val) const noexcept
{
// See: https://man7.org/linux/man-pages/man2/futex.2.html
static_assert(sizeof(std::atomic<size_type>) == 4);
syscall(SYS_futex, &_value, futex_op, val, nullptr, nullptr, 0);
}
#endif
std::atomic<size_type> _value{ 0 };
#if _TIL_SPSC_DETAIL_POSITION_IMPL_FALLBACK
private:
std::mutex _m;
std::condition_variable _cv;
#endif
};
#endif
template<typename T>
inline T* alloc_raw_memory(size_t size)
{
constexpr auto alignment = alignof(T);
if constexpr (alignment <= __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
return static_cast<T*>(::operator new(size));
}
else
{
return static_cast<T*>(::operator new(size, std::align_val_t(alignment)));
}
}
template<typename T>
inline void free_raw_memory(T* ptr) noexcept
{
constexpr auto alignment = alignof(T);
if constexpr (alignment <= __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
::operator delete(ptr);
}
else
{
::operator delete(ptr, std::align_val_t(alignment));
}
}
struct acquisition
{
// The index range [begin, end) is the range of slots in the array returned by
// arc<T>::data() that may be written to / read from respectively.
// If a range has been successfully acquired "end > begin" is true. end thus can't be 0.
size_type begin;
size_type end;
// Upon release() of an acquisition, next is the value that's written to the consumer/producer position.
// It's basically the same as end, but with the revolution flag mixed in.
// If end is equal to capacity, next will be 0 (mixed with the next revolution flag).
size_type next;
// If the other side of the queue hasn't been destroyed yet, alive will be true.
bool alive;
constexpr acquisition(size_type begin, size_type end, size_type next, bool alive) :
begin(begin),
end(end),
next(next),
alive(alive)
{
}
};
// The following assumes you know what ring/circular buffers are. You can read about them here:
// https://en.wikipedia.org/wiki/Circular_buffer
//
// Furthermore the implementation solves a problem known as the producer-consumer problem:
// https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem
//
// arc follows the classic spsc design and manages a ring buffer with two positions: _producer and _consumer.
// They contain the position the producer / consumer will next write to / read from respectively.
// As usual with ring buffers, these positions are modulo to the _capacity of the underlying buffer.
// The producer's writable range is [_producer, _consumer) and the consumer's readable is [_consumer, _producer).
//
// After you wrote the numbers 0 to 6 into a queue of size 10, a typical state of the ring buffer might be:
// [ 0 | 1 | 2 | 3 | 4 | 5 | 6 | _ | _ | _ | _ ]
// ^ ^ ^
// _consumer = 0 _producer = 7 _capacity = 10
//
// As you can see the readable range currently is [_consumer, _producer) = [0, 7).
// The remaining writable range on the other hand is [_producer, _consumer) = [7, 0).
// Wait, what? [7, 0)? How does that work? As all positions are modulo _capacity, 0 mod 10 is the same as 10 mod 10.
// If we only want to read forward in the buffer [7, 0) is thus the same as [7, 10).
//
// If we read 3 items from the queue the contents will be:
// [ _ | _ | _ | 3 | 4 | 5 | 6 | _ | _ | _ | _ ]
// ^ ^
// _consumer = 3 _producer = 7
//
// Now the writable range is still [_producer, _consumer), but it wraps around the end of the ring buffer.
// In this case arc will split the range in two and return each separately in acquire().
// The first returned range will be [_producer, _capacity) and the second [0, _consumer).
// The same logic applies if the readable range wraps around the end of the ring buffer.
//
// As these are symmetric, the logic for acquiring and releasing ranges is the same for both sides.
// The producer will acquire() and release() ranges with its own position as "mine" and the consumer's
// position as "theirs". These arguments are correspondingly flipped for the consumer.
//
// As part of the producer-consumer problem, the producer cannot write more values ahead of the
// consumer than the buffer's capacity. Since both positions are modulo to the capacity we can only
// determine positional differences smaller than the capacity. Due to that both producer and
// consumer store a "revolution_flag" as the second highest bit within their positions.
// This bit is flipped each time the producer/consumer wrap around the end of the ring buffer.
// If the positions are identical, except for their "revolution_flag" value, the producer thus must
// be capacity-many positions ahead of the consumer and must wait until items have been consumed.
//
// Inversely the consumer must wait until the producer has written at least one value ahead.
// This can be detected by checking whether the positions are identical including the revolution_flag.
template<typename T>
struct arc
{
explicit arc(size_type capacity) noexcept :
_data(alloc_raw_memory<T>(size_t(capacity) * sizeof(T))),
_capacity(capacity)
{
}
~arc()
{
auto beg = _consumer.load(std::memory_order_acquire);
auto end = _producer.load(std::memory_order_acquire);
auto differentRevolution = ((beg ^ end) & revolution_flag) != 0;
beg &= position_mask;
end &= position_mask;
// The producer position will always be ahead of the consumer, but since we're dealing
// with a ring buffer the producer may be wrapped around the end of the buffer.
// We thus need to deal with 3 potential cases:
// * No valid data.
// If both positions including their revolution bits are identical.
// * Valid data in the middle of the ring buffer.
// If _producer > _consumer.
// * Valid data at both ends of the ring buffer.
// If the revolution bits differ, even if the positions are otherwise identical,
// which they might be if the channel contains exactly as many values as its capacity.
if (end > beg)
{
std::destroy(_data + beg, _data + end);
}
else if (differentRevolution)
{
std::destroy(_data, _data + end);
std::destroy(_data + beg, _data + _capacity);
}
free_raw_memory(_data);
}
void drop_producer()
{
drop(_producer);
}
void drop_consumer()
{
drop(_consumer);
}
acquisition producer_acquire(size_type slots, bool blocking) noexcept
{
return acquire(_producer, _consumer, revolution_flag, slots, blocking);
}
void producer_release(acquisition acquisition) noexcept
{
release(_producer, acquisition);
}
acquisition consumer_acquire(size_type slots, bool blocking) noexcept
{
return acquire(_consumer, _producer, 0, slots, blocking);
}
void consumer_release(acquisition acquisition) noexcept
{
release(_consumer, acquisition);
}
T* data() const noexcept
{
return _data;
}
private:
void drop(atomic_size_type& mine)
{
// Signal the other side we're dropped. See acquire() for the handling of the drop_flag.
// We don't need to use release ordering like release() does as each call to
// any of the producer/consumer methods already results in a call to release().
// Another release ordered write can't possibly synchronize any more data anyways at this point.
const auto myPos = mine.load(std::memory_order_relaxed);
mine.store(myPos | drop_flag, std::memory_order_relaxed);
mine.notify_one();
// The first time SPSCBase is dropped (destroyed) we'll set
// the flag to true and get false, causing us to return early.
// Only the second time we'll get true.
// --> The contents are only deleted when both sides have been dropped.
if (_eitherSideDropped.exchange(true, std::memory_order_relaxed))
{
delete this;
}
}
// NOTE: waitMask MUST be either 0 (consumer) or revolution_flag (producer).
acquisition acquire(atomic_size_type& mine, atomic_size_type& theirs, size_type waitMask, size_type slots, bool blocking) noexcept
{
size_type myPos = mine.load(std::memory_order_relaxed);
size_type theirPos;
while (true)
{
// This acquire read synchronizes with the release write in release().
theirPos = theirs.load(std::memory_order_acquire);
if ((myPos ^ theirPos) != waitMask)
{
break;
}
if (!blocking)
{
return {
0,
0,
0,
true,
};
}
theirs.wait(theirPos, std::memory_order_relaxed);
}
// If the other side's position contains a drop flag, as a X -> we need to...
// * producer -> stop immediately
// FYI: isProducer == (waitMask != 0).
// * consumer -> finish consuming all values and then stop
// We're finished if the only difference between our
// and the other side's position is the drop flag.
if ((theirPos & drop_flag) != 0 && (waitMask != 0 || (myPos ^ theirPos) == drop_flag))
{
return {
0,
0,
0,
false,
};
}
auto begin = myPos & position_mask;
auto end = theirPos & position_mask;
// [begin, end) is the writable/readable range for the producer/consumer.
// The following detects whether we'd be wrapping around the end of the ring buffer
// and splits the range into the first half [mine, _capacity).
// If acquire() is called again it'll return [0, theirs).
end = end > begin ? end : _capacity;
// Of course we also need to ensure to not return more than we've been asked for.
end = std::min(end, begin + slots);
// "next" will contain the value that's stored into "mine" when release() is called.
// It's basically the same as "end", but with the revolution flag spliced in.
// If we acquired the range [mine, _capacity) "end" will equal _capacity
// and thus wrap around the ring buffer. The next value for "mine" is thus the
// position zero | the flipped "revolution" (and 0 | x == x).
auto revolution = myPos & revolution_flag;
auto next = end != _capacity ? end | revolution : revolution ^ revolution_flag;
return {
begin,
end,
next,
true,
};
}
void release(atomic_size_type& mine, acquisition acquisition) noexcept
{
// This release write synchronizes with the acquire read in acquire().
mine.store(acquisition.next, std::memory_order_release);
mine.notify_one();
}
T* const _data;
const size_type _capacity;
std::atomic<bool> _eitherSideDropped{ false };
atomic_size_type _producer;
atomic_size_type _consumer;
};
inline void validate_size(size_t v)
{
if (v > static_cast<size_t>(position_mask))
{
throw std::overflow_error{ "size too large for spsc" };
}
}
}
// Block until at least one item has been written into the sender / read from the receiver.
inline constexpr details::block_initially_policy block_initially{};
// Block until all items have been written into the sender / read from the receiver.
inline constexpr details::block_forever_policy block_forever{};
template<typename T>
struct producer
{
explicit producer(details::arc<T>* arc) noexcept :
_arc(arc) {}
producer<T>(const producer<T>&) = delete;
producer<T>& operator=(const producer<T>&) = delete;
producer(producer<T>&& other) noexcept
{
drop();
_arc = std::exchange(other._arc, nullptr);
}
producer<T>& operator=(producer<T>&& other) noexcept
{
drop();
_arc = std::exchange(other._arc, nullptr);
}
~producer()
{
drop();
}
// emplace constructs an item in-place at the end of the queue.
// It returns true, if the item was successfully placed within the queue.
// The return value will be false, if the consumer is gone.
template<typename... Args>
bool emplace(Args&&... args) const
{
auto acquisition = _arc->producer_acquire(1, true);
if (!acquisition.end)
{
return false;
}
auto data = _arc->data();
auto begin = data + acquisition.begin;
new (begin) T(std::forward<Args>(args)...);
_arc->producer_release(acquisition);
return true;
}
template<typename InputIt>
std::pair<size_t, bool> push(InputIt first, InputIt last) const
{
return push_n(block_forever, first, std::distance(first, last));
}
// push writes the items between first and last into the queue.
// The amount of successfully written items is returned as the first pair field.
// The second pair field will be false if the consumer is gone.
template<typename WaitPolicy, typename InputIt, details::enable_if_wait_policy_t<WaitPolicy> = 0>
std::pair<size_t, bool> push(WaitPolicy&& policy, InputIt first, InputIt last) const
{
return push_n(std::forward<WaitPolicy>(policy), first, std::distance(first, last));
}
template<typename InputIt>
std::pair<size_t, bool> push_n(InputIt first, size_t count) const
{
return push_n(block_forever, first, count);
}
// push_n writes count items from first into the queue.
// The amount of successfully written items is returned as the first pair field.
// The second pair field will be false if the consumer is gone.
template<typename WaitPolicy, typename InputIt, details::enable_if_wait_policy_t<WaitPolicy> = 0>
std::pair<size_t, bool> push_n(WaitPolicy&&, InputIt first, size_t count) const
{
details::validate_size(count);
const auto data = _arc->data();
auto remaining = static_cast<size_type>(count);
auto blocking = true;
auto ok = true;
while (remaining != 0)
{
auto acquisition = _arc->producer_acquire(remaining, blocking);
if (!acquisition.end)
{
ok = acquisition.alive;
break;
}
const auto begin = data + acquisition.begin;
const auto got = acquisition.end - acquisition.begin;
std::uninitialized_copy_n(first, got, begin);
first += got;
remaining -= got;
_arc->producer_release(acquisition);
if constexpr (!std::remove_reference_t<WaitPolicy>::_block_forever)
{
blocking = false;
}
}
return { count - remaining, ok };
}
private:
void drop()
{
if (_arc)
{
_arc->drop_producer();
}
}
details::arc<T>* _arc = nullptr;
};
template<typename T>
struct consumer
{
explicit consumer(details::arc<T>* arc) noexcept :
_arc(arc) {}
consumer<T>(const consumer<T>&) = delete;
consumer<T>& operator=(const consumer<T>&) = delete;
consumer(consumer<T>&& other) noexcept
{
drop();
_arc = std::exchange(other._arc, nullptr);
}
consumer<T>& operator=(consumer<T>&& other) noexcept
{
drop();
_arc = std::exchange(other._arc, nullptr);
}
~consumer()
{
drop();
}
// pop returns the next item in the queue, or std::nullopt if the producer is gone.
std::optional<T> pop() const
{
auto acquisition = _arc->consumer_acquire(1, true);
if (!acquisition.end)
{
return std::nullopt;
}
auto data = _arc->data();
auto begin = data + acquisition.begin;
auto item = std::move(*begin);
std::destroy_at(begin);
_arc->consumer_release(acquisition);
return item;
}
template<typename OutputIt>
std::pair<size_t, bool> pop_n(OutputIt first, size_t count) const
{
return pop_n(block_forever, first, count);
}
// pop_n reads up to count items into first.
// The amount of successfully read items is returned as the first pair field.
// The second pair field will be false if the consumer is gone.
template<typename WaitPolicy, typename OutputIt, details::enable_if_wait_policy_t<WaitPolicy> = 0>
std::pair<size_t, bool> pop_n(WaitPolicy&&, OutputIt first, size_t count) const
{
details::validate_size(count);
const auto data = _arc->data();
auto remaining = static_cast<size_type>(count);
auto blocking = true;
auto ok = true;
while (remaining != 0)
{
auto acquisition = _arc->consumer_acquire(remaining, blocking);
if (!acquisition.end)
{
ok = acquisition.alive;
break;
}
auto beg = data + acquisition.begin;
auto end = data + acquisition.end;
auto got = acquisition.end - acquisition.begin;
first = std::move(beg, end, first);
std::destroy(beg, end);
remaining -= got;
_arc->consumer_release(acquisition);
if constexpr (!std::remove_reference_t<WaitPolicy>::_block_forever)
{
blocking = false;
}
}
return { count - remaining, ok };
}
private:
void drop()
{
if (_arc)
{
_arc->drop_consumer();
}
}
details::arc<T>* _arc = nullptr;
};
// channel returns a bounded, lock-free, single-producer, single-consumer
// FIFO queue ("channel") with the given maximum capacity.
template<typename T>
std::pair<producer<T>, consumer<T>> channel(uint32_t capacity)
{
if (capacity == 0)
{
throw std::invalid_argument{ "invalid capacity" };
}
const auto arc = new details::arc<T>(capacity);
return { std::piecewise_construct, std::forward_as_tuple(arc), std::forward_as_tuple(arc) };
}
}

View File

@@ -26,13 +26,12 @@ Renderer::Renderer(IRenderData* pData,
_In_reads_(cEngines) IRenderEngine** const rgpEngines,
const size_t cEngines,
std::unique_ptr<IRenderThread> thread) :
_pData(pData),
_pData(THROW_HR_IF_NULL(E_INVALIDARG, pData)),
_pThread{ std::move(thread) },
_destructing{ false },
_clusterBuffer{}
_clusterBuffer{},
_viewport{ pData->GetViewport() }
{
_srViewportPrevious = { 0 };
for (size_t i = 0; i < cEngines; i++)
{
IRenderEngine* engine = rgpEngines[i];
@@ -208,7 +207,7 @@ void Renderer::TriggerSystemRedraw(const RECT* const prcDirtyClient)
// - <none>
void Renderer::TriggerRedraw(const Viewport& region)
{
Viewport view = _pData->GetViewport();
Viewport view = _viewport;
SMALL_RECT srUpdateRegion = region.ToExclusive();
if (view.TrimToViewport(&srUpdateRegion))
@@ -357,7 +356,7 @@ void Renderer::TriggerSelection()
// - True if something changed and we scrolled. False otherwise.
bool Renderer::_CheckViewportAndScroll()
{
SMALL_RECT const srOldViewport = _srViewportPrevious;
SMALL_RECT const srOldViewport = _viewport.ToInclusive();
SMALL_RECT const srNewViewport = _pData->GetViewport().ToInclusive();
COORD coordDelta;
@@ -369,7 +368,7 @@ bool Renderer::_CheckViewportAndScroll()
LOG_IF_FAILED(engine->UpdateViewport(srNewViewport));
}
_srViewportPrevious = srNewViewport;
_viewport = Viewport::FromInclusive(srNewViewport);
// If we're keeping some buffers between calls, let them know about the viewport size
// so they can prepare the buffers for changes to either preallocate memory at once

View File

@@ -120,7 +120,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _PerformScrolling(_In_ IRenderEngine* const pEngine);
SMALL_RECT _srViewportPrevious;
Microsoft::Console::Types::Viewport _viewport;
static constexpr float _shrinkThreshold = 0.8f;
std::vector<Cluster> _clusterBuffer;

View File

@@ -83,7 +83,6 @@ DxEngine::DxEngine() :
_glyphCell{},
_boxDrawingEffect{},
_haveDeviceResources{ false },
_swapChainHandle{ INVALID_HANDLE_VALUE },
_swapChainDesc{ 0 },
_swapChainFrameLatencyWaitableObject{ INVALID_HANDLE_VALUE },
_recreateDeviceRequested{ false },
@@ -456,7 +455,8 @@ try
switch (_chainMode)
{
case SwapChainMode::ForHwnd: {
case SwapChainMode::ForHwnd:
{
// use the HWND's dimensions for the swap chain dimensions.
RECT rect = { 0 };
RETURN_IF_WIN32_BOOL_FALSE(GetClientRect(_hwndTarget, &rect));
@@ -485,11 +485,8 @@ try
break;
}
case SwapChainMode::ForComposition: {
RETURN_IF_FAILED(DCompositionCreateSurfaceHandle(GENERIC_ALL, nullptr, &_swapChainHandle));
RETURN_IF_FAILED(_dxgiFactory2.As(&_dxgiFactoryMedia));
case SwapChainMode::ForComposition:
{
// Use the given target size for compositions.
_swapChainDesc.Width = _displaySizePixels.width<UINT>();
_swapChainDesc.Height = _displaySizePixels.height<UINT>();
@@ -499,11 +496,10 @@ try
// It's 100% required to use scaling mode stretch for composition. There is no other choice.
_swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
RETURN_IF_FAILED(_dxgiFactoryMedia->CreateSwapChainForCompositionSurfaceHandle(_d3dDevice.Get(),
_swapChainHandle.get(),
&_swapChainDesc,
nullptr,
&_dxgiSwapChain));
RETURN_IF_FAILED(_dxgiFactory2->CreateSwapChainForComposition(_d3dDevice.Get(),
&_swapChainDesc,
nullptr,
&_dxgiSwapChain));
break;
}
default:
@@ -829,14 +825,14 @@ try
}
CATCH_LOG()
HANDLE DxEngine::GetSwapChainHandle()
Microsoft::WRL::ComPtr<IDXGISwapChain1> DxEngine::GetSwapChain()
{
if (!_swapChainHandle)
if (_dxgiSwapChain.Get() == nullptr)
{
THROW_IF_FAILED(_CreateDeviceResources(true));
}
return _swapChainHandle.get();
return _dxgiSwapChain;
}
void DxEngine::_InvalidateRectangle(const til::rectangle& rc)
@@ -993,13 +989,15 @@ CATCH_RETURN();
{
switch (_chainMode)
{
case SwapChainMode::ForHwnd: {
case SwapChainMode::ForHwnd:
{
RECT clientRect = { 0 };
LOG_IF_WIN32_BOOL_FALSE(GetClientRect(_hwndTarget, &clientRect));
return til::rectangle{ clientRect }.size();
}
case SwapChainMode::ForComposition: {
case SwapChainMode::ForComposition:
{
return _sizeTarget;
}
default:
@@ -2231,10 +2229,12 @@ CATCH_RETURN();
switch (_chainMode)
{
case SwapChainMode::ForHwnd: {
case SwapChainMode::ForHwnd:
{
return D2D1::ColorF(rgb);
}
case SwapChainMode::ForComposition: {
case SwapChainMode::ForComposition:
{
// Get the A value we've snuck into the highest byte
const BYTE a = ((color >> 24) & 0xFF);
const float aFloat = a / 255.0f;

View File

@@ -63,7 +63,7 @@ namespace Microsoft::Console::Render
void SetSoftwareRendering(bool enable) noexcept;
HANDLE GetSwapChainHandle();
::Microsoft::WRL::ComPtr<IDXGISwapChain1> GetSwapChain();
// IRenderEngine Members
[[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override;
@@ -190,11 +190,9 @@ namespace Microsoft::Console::Render
::Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> _d2dBrushBackground;
::Microsoft::WRL::ComPtr<IDXGIFactory2> _dxgiFactory2;
::Microsoft::WRL::ComPtr<IDXGIFactoryMedia> _dxgiFactoryMedia;
::Microsoft::WRL::ComPtr<IDXGIDevice> _dxgiDevice;
::Microsoft::WRL::ComPtr<IDXGISurface> _dxgiSurface;
wil::unique_handle _swapChainHandle;
DXGI_SWAP_CHAIN_DESC1 _swapChainDesc;
::Microsoft::WRL::ComPtr<IDXGISwapChain1> _dxgiSwapChain;
wil::unique_handle _swapChainFrameLatencyWaitableObject;

View File

@@ -21,8 +21,6 @@
#include <typeinfo>
#include <stdexcept>
#include <dcomp.h>
#include <dxgi.h>
#include <dxgi1_2.h>
#include <dxgi1_3.h>

View File

@@ -0,0 +1,195 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "WexTestClass.h"
using namespace WEX::Common;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
struct drop_indicator
{
explicit drop_indicator(int& counter) noexcept :
_counter(&counter) {}
drop_indicator(const drop_indicator&) = delete;
drop_indicator& operator=(const drop_indicator&) = delete;
drop_indicator(drop_indicator&& other) noexcept
{
_counter = std::exchange(other._counter, nullptr);
}
drop_indicator& operator=(drop_indicator&& other) noexcept
{
_counter = std::exchange(other._counter, nullptr);
}
~drop_indicator()
{
if (_counter)
{
++*_counter;
}
}
private:
int* _counter = nullptr;
};
template<typename T>
void drop(T&& val)
{
auto _ = std::move(val);
}
class SPSCTests
{
BEGIN_TEST_CLASS(SPSCTests)
TEST_CLASS_PROPERTY(L"TestTimeout", L"0:0:10") // 10s timeout
END_TEST_CLASS()
TEST_METHOD(DropEmptyTest);
TEST_METHOD(DropSameRevolutionTest);
TEST_METHOD(DropDifferentRevolutionTest);
TEST_METHOD(IntegrationTest);
};
void SPSCTests::DropEmptyTest()
{
auto [tx, rx] = til::spsc::channel<drop_indicator>(5);
int counter = 0;
for (int i = 0; i < 5; ++i)
{
tx.emplace(counter);
}
VERIFY_ARE_EQUAL(counter, 0);
for (int i = 0; i < 5; ++i)
{
rx.pop();
}
VERIFY_ARE_EQUAL(counter, 5);
for (int i = 0; i < 3; ++i)
{
tx.emplace(counter);
}
VERIFY_ARE_EQUAL(counter, 5);
drop(tx);
VERIFY_ARE_EQUAL(counter, 5);
for (int i = 0; i < 3; ++i)
{
rx.pop();
}
VERIFY_ARE_EQUAL(counter, 8);
drop(rx);
VERIFY_ARE_EQUAL(counter, 8);
}
void SPSCTests::DropSameRevolutionTest()
{
auto [tx, rx] = til::spsc::channel<drop_indicator>(5);
int counter = 0;
for (int i = 0; i < 5; ++i)
{
tx.emplace(counter);
}
VERIFY_ARE_EQUAL(counter, 0);
drop(tx);
VERIFY_ARE_EQUAL(counter, 0);
for (int i = 0; i < 3; ++i)
{
rx.pop();
}
VERIFY_ARE_EQUAL(counter, 3);
drop(rx);
VERIFY_ARE_EQUAL(counter, 5);
}
void SPSCTests::DropDifferentRevolutionTest()
{
auto [tx, rx] = til::spsc::channel<drop_indicator>(5);
int counter = 0;
for (int i = 0; i < 4; ++i)
{
tx.emplace(counter);
}
VERIFY_ARE_EQUAL(counter, 0);
for (int i = 0; i < 3; ++i)
{
rx.pop();
}
VERIFY_ARE_EQUAL(counter, 3);
for (int i = 0; i < 4; ++i)
{
tx.emplace(counter);
}
VERIFY_ARE_EQUAL(counter, 3);
// At this point we emplace()d 8 items and pop()ed 3 in a channel with a capacity of 5.
// Both producer and consumer positions will be 3 and only differ in their revolution flag.
// This ensures that the arc<T> destructor works even if the
// two positions within the circular buffer are identical (modulo the capacity).
drop(tx);
VERIFY_ARE_EQUAL(counter, 3);
drop(rx);
VERIFY_ARE_EQUAL(counter, 8);
}
void SPSCTests::IntegrationTest()
{
auto [tx, rx] = til::spsc::channel<int>(7);
std::thread t([tx = std::move(tx)]() {
std::array<int, 11> buffer{};
std::generate(buffer.begin(), buffer.end(), [v = 0]() mutable { return v++; });
for (int i = 0; i < 37; ++i)
{
tx.emplace(i);
}
for (int i = 0; i < 3; ++i)
{
tx.push(buffer.begin(), buffer.end());
}
});
std::array<int, 11> buffer{};
for (int i = 0; i < 3; ++i)
{
rx.pop_n(buffer.data(), buffer.size());
for (int j = 0; j < 11; ++j)
{
VERIFY_ARE_EQUAL(i * 11 + j, buffer[j]);
}
}
for (int i = 33; i < 37; ++i)
{
auto actual = rx.pop();
VERIFY_ARE_EQUAL(i, actual);
}
for (int i = 0; i < 33; ++i)
{
auto expected = i % 11;
auto actual = rx.pop();
VERIFY_ARE_EQUAL(expected, actual);
}
t.join();
}

View File

@@ -22,6 +22,7 @@
<ClCompile Include="..\precomp.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="SPSCTests.cpp" />
<ClCompile Include="u8u16convertTests.cpp" />
</ItemGroup>
<ItemGroup>

View File

@@ -15,6 +15,7 @@
<ClCompile Include="OperatorTests.cpp" />
<ClCompile Include="MathTests.cpp" />
<ClCompile Include="BaseTests.cpp" />
<ClCompile Include="SPSCTests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\precomp.h" />

View File

@@ -145,7 +145,9 @@ const COORD UiaTextRangeBase::GetEndpoint(TextPatternRangeEndpoint endpoint) con
// - true if range is degenerate, false otherwise.
bool UiaTextRangeBase::SetEndpoint(TextPatternRangeEndpoint endpoint, const COORD val) noexcept
{
const auto bufferSize = _getBufferSize();
// GH#6402: Get the actual buffer size here, instead of the one
// constrained by the virtual bottom.
const auto bufferSize = _pData->GetTextBuffer().GetSize();
switch (endpoint)
{
case TextPatternRangeEndpoint_End:
@@ -284,6 +286,8 @@ IFACEMETHODIMP UiaTextRangeBase::ExpandToEnclosingUnit(_In_ TextUnit unit) noexc
}
else
{
// TODO GH#6986: properly handle "end of buffer" as last character
// instead of last cell
// expand to document
_start = bufferSize.Origin();
_end = bufferSize.EndExclusive();
@@ -393,7 +397,9 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_
// set of coords.
std::vector<double> coords;
const auto bufferSize = _getBufferSize();
// GH#6402: Get the actual buffer size here, instead of the one
// constrained by the virtual bottom.
const auto bufferSize = _pData->GetTextBuffer().GetSize();
// these viewport vars are converted to the buffer coordinate space
const auto viewport = bufferSize.ConvertToOrigin(_pData->GetViewport());

View File

@@ -116,8 +116,12 @@ set "__PROJECT_NAME=!_OUTPUT!"
rem If we're trying to clean build, make sure to update the target here.
if "%_MSBUILD_TARGET%" == "Build" (
set __MSBUILD_TARGET=%__PROJECT_NAME%
) else if "%_MSBUILD_TARGET%" == "Clean,Build" (
) else if "%_MSBUILD_TARGET%" == "Clean;Build" (
set __MSBUILD_TARGET=%__PROJECT_NAME%:Rebuild
) else (
echo.
echo Oops... build bug in the neighborhood of configuring a build target.
echo.
)
rem This statement will propagate our internal variables up to the calling
rem scope. Because they're all on one line, the value of our local variables