mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-07 06:39:44 +00:00
Compare commits
37 Commits
dev/lhecke
...
dev/miniks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b077abb445 | ||
|
|
f9324d062d | ||
|
|
35cae5a33d | ||
|
|
a8be923688 | ||
|
|
1eea75e3e7 | ||
|
|
ad723f9671 | ||
|
|
4db39a6f55 | ||
|
|
d7255fdbef | ||
|
|
23aef43c81 | ||
|
|
8c1a45f6f0 | ||
|
|
ebe9016356 | ||
|
|
d4885149ae | ||
|
|
ee5c5a474b | ||
|
|
4aa62f9edd | ||
|
|
cc6ad0b99b | ||
|
|
28e1e226ad | ||
|
|
6f23280011 | ||
|
|
559e700228 | ||
|
|
93ab856ab8 | ||
|
|
bfd398f609 | ||
|
|
5ab3064f07 | ||
|
|
2bc4749f65 | ||
|
|
2168ee441a | ||
|
|
c3ec32539a | ||
|
|
40323e7c1d | ||
|
|
627613f649 | ||
|
|
60b089e7b0 | ||
|
|
821c39c2a3 | ||
|
|
3f23ec3465 | ||
|
|
37dab43af0 | ||
|
|
d77e55596b | ||
|
|
0be1c9deef | ||
|
|
5f9321310f | ||
|
|
dad044a405 | ||
|
|
061e636163 | ||
|
|
8aaa93f139 | ||
|
|
90a24b20b8 |
25
.github/actions/spell-check/advice.txt
vendored
25
.github/actions/spell-check/advice.txt
vendored
@@ -1,25 +0,0 @@
|
||||
<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.
|
||||
36
.github/actions/spell-check/dictionary/apis.txt
vendored
36
.github/actions/spell-check/dictionary/apis.txt
vendored
@@ -1,36 +0,0 @@
|
||||
ACCEPTFILES
|
||||
ACCESSDENIED
|
||||
bitfield
|
||||
bitfields
|
||||
CLASSNOTAVAILABLE
|
||||
EXPCMDFLAGS
|
||||
EXPCMDSTATE
|
||||
fullkbd
|
||||
href
|
||||
IAsync
|
||||
IBox
|
||||
IBind
|
||||
IClass
|
||||
IComparable
|
||||
ICustom
|
||||
IDialog
|
||||
IDirect
|
||||
IExplorer
|
||||
IMap
|
||||
IObject
|
||||
IStorage
|
||||
LCID
|
||||
LSHIFT
|
||||
NCHITTEST
|
||||
NCLBUTTONDBLCLK
|
||||
NCRBUTTONDBLCLK
|
||||
NOAGGREGATION
|
||||
NOREDIRECTIONBITMAP
|
||||
oaidl
|
||||
ocidl
|
||||
RETURNCMD
|
||||
rfind
|
||||
roundf
|
||||
RSHIFT
|
||||
SIZENS
|
||||
tmp
|
||||
479829
.github/actions/spell-check/dictionary/dictionary.txt
vendored
479829
.github/actions/spell-check/dictionary/dictionary.txt
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
powf
|
||||
sqrtf
|
||||
isnan
|
||||
@@ -1,15 +0,0 @@
|
||||
ACLs
|
||||
backplating
|
||||
DACL
|
||||
DACLs
|
||||
LKG
|
||||
mfcribbon
|
||||
microsoft
|
||||
microsoftonline
|
||||
osgvsowi
|
||||
powerrename
|
||||
powershell
|
||||
SACLs
|
||||
tdbuildteamid
|
||||
vcruntime
|
||||
visualstudio
|
||||
63
.github/actions/spell-check/excludes.txt
vendored
63
.github/actions/spell-check/excludes.txt
vendored
@@ -1,63 +0,0 @@
|
||||
(?:^|/)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$
|
||||
15
.github/actions/spell-check/expect/web.txt
vendored
15
.github/actions/spell-check/expect/web.txt
vendored
@@ -1,15 +0,0 @@
|
||||
http
|
||||
td
|
||||
www
|
||||
ecma
|
||||
rapidtables
|
||||
WCAG
|
||||
freedesktop
|
||||
ycombinator
|
||||
robertelder
|
||||
kovidgoyal
|
||||
leonerd
|
||||
fixterms
|
||||
uk
|
||||
winui
|
||||
appshellintegration
|
||||
@@ -1,21 +0,0 @@
|
||||
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\+/"
|
||||
15
.github/actions/spelling/README.md
vendored
Normal file
15
.github/actions/spelling/README.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
48
.github/actions/spelling/advice.md
vendored
Normal file
48
.github/actions/spelling/advice.md
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<!-- 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>
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dictionaries are lists of words to accept unconditionally
|
||||
# Allow files are lists of words to accept unconditionally
|
||||
|
||||
While check spelling will complain about a whitelisted word
|
||||
While check spelling will complain about an expected word
|
||||
which is no longer present, you can include things here even if
|
||||
they are not otherwise present in the repository.
|
||||
|
||||
@@ -8,13 +8,14 @@ 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 |
|
||||
| ---- | ----------- |
|
||||
| [Dictionary](dictionary.txt) | Primary US English dictionary |
|
||||
| [Allow](allow.txt) | Supplements to the 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 |
|
||||
108
.github/actions/spelling/allow/allow.txt
vendored
Normal file
108
.github/actions/spelling/allow/allow.txt
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
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
|
||||
248
.github/actions/spelling/allow/apis.txt
vendored
Normal file
248
.github/actions/spelling/allow/apis.txt
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
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
|
||||
117
.github/actions/spelling/allow/colors.txt
vendored
Normal file
117
.github/actions/spelling/allow/colors.txt
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
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
|
||||
@@ -1,8 +1,10 @@
|
||||
Consolas
|
||||
emoji
|
||||
emojis
|
||||
Extralight
|
||||
Gabriola
|
||||
Iosevka
|
||||
MDL
|
||||
Monofur
|
||||
Segoe
|
||||
wght
|
||||
11
.github/actions/spelling/allow/math.txt
vendored
Normal file
11
.github/actions/spelling/allow/math.txt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
atan
|
||||
CPrime
|
||||
HBar
|
||||
HPrime
|
||||
isnan
|
||||
LPrime
|
||||
LStep
|
||||
powf
|
||||
RSub
|
||||
sqrtf
|
||||
ULP
|
||||
85
.github/actions/spelling/allow/microsoft.txt
vendored
Normal file
85
.github/actions/spelling/allow/microsoft.txt
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
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
|
||||
@@ -1,43 +1,66 @@
|
||||
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
|
||||
@@ -45,11 +68,18 @@ Pham
|
||||
Rincewind
|
||||
rprichard
|
||||
Schoonover
|
||||
shadertoy
|
||||
Shomnipotence
|
||||
simioni
|
||||
Somuah
|
||||
sonph
|
||||
sonpham
|
||||
stakx
|
||||
talo
|
||||
thereses
|
||||
Walisch
|
||||
WDX
|
||||
Wellons
|
||||
Wirt
|
||||
Wojciech
|
||||
zadjii
|
||||
523
.github/actions/spelling/candidate.patterns
vendored
Normal file
523
.github/actions/spelling/candidate.patterns
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
# 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
|
||||
(['"]|")[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-)/
|
||||
117
.github/actions/spelling/excludes.txt
vendored
Normal file
117
.github/actions/spelling/excludes.txt
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
# 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$
|
||||
@@ -1,22 +1,31 @@
|
||||
abcde
|
||||
abcdef
|
||||
ABCDEFG
|
||||
ABCDEFGH
|
||||
AAAa
|
||||
AAAAA
|
||||
AAAAAAAAAAAAA
|
||||
AAAAAABBBBBBCCC
|
||||
AAAAABBBBBBCCC
|
||||
abcd
|
||||
abcd
|
||||
ABCDEFGHIJ
|
||||
abcdefghijk
|
||||
ABCDEFGHIJKLMNO
|
||||
abcdefghijklmnop
|
||||
ABCDEFGHIJKLMNOPQRST
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
ABCG
|
||||
ABE
|
||||
abf
|
||||
BBBBB
|
||||
BBBBBBBB
|
||||
BBBBBCCC
|
||||
BBBBCCCCC
|
||||
BBGGRR
|
||||
BBBBBBBBBBBBBBDDDD
|
||||
EFG
|
||||
EFGh
|
||||
QQQQQQQQQQABCDEFGHIJ
|
||||
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQ
|
||||
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
|
||||
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
|
||||
qrstuvwxyz
|
||||
qwerty
|
||||
QWERTYUIOP
|
||||
qwertyuiopasdfg
|
||||
YYYYYYYDDDDDDDDDDD
|
||||
ZAAZZ
|
||||
@@ -28,3 +37,4 @@ ZYXWVUT
|
||||
ZZBBZ
|
||||
ZZZBB
|
||||
ZZZBZ
|
||||
ZZZZZ
|
||||
File diff suppressed because it is too large
Load Diff
6
.github/actions/spelling/expect/web.txt
vendored
Normal file
6
.github/actions/spelling/expect/web.txt
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
WCAG
|
||||
winui
|
||||
appshellintegration
|
||||
mdtauk
|
||||
gfycat
|
||||
Guake
|
||||
62
.github/actions/spelling/line_forbidden.patterns
vendored
Normal file
62
.github/actions/spelling/line_forbidden.patterns
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# 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
|
||||
96
.github/actions/spelling/patterns/patterns.txt
vendored
Normal file
96
.github/actions/spelling/patterns/patterns.txt
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
# 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
|
||||
12
.github/actions/spelling/reject.txt
vendored
Normal file
12
.github/actions/spelling/reject.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
^attache$
|
||||
^attacher$
|
||||
^attachers$
|
||||
benefitting
|
||||
occurences?
|
||||
^dependan.*
|
||||
^oer$
|
||||
Sorce
|
||||
^[Ss]pae.*
|
||||
^untill$
|
||||
^untilling$
|
||||
^wether.*
|
||||
20
.github/workflows/spelling.yml
vendored
20
.github/workflows/spelling.yml
vendored
@@ -1,20 +0,0 @@
|
||||
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
|
||||
134
.github/workflows/spelling2.yml
vendored
Normal file
134
.github/workflows/spelling2.yml
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
# 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 }}
|
||||
@@ -108,7 +108,12 @@ TextAttribute ATTR_ROW::GetAttrByColumn(const size_t column,
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, column >= _cchRowWidth);
|
||||
const auto runPos = FindAttrIndex(column, pApplies);
|
||||
return _list.at(runPos).GetAttributes();
|
||||
return GetAttrByIndex(runPos);
|
||||
}
|
||||
|
||||
TextAttribute ATTR_ROW::GetAttrByIndex(const size_t index) const
|
||||
{
|
||||
return _list.at(index).GetAttributes();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -250,11 +255,11 @@ void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAtt
|
||||
if (newAttrs.size() == 1)
|
||||
{
|
||||
// Get the new color attribute we're trying to apply
|
||||
const TextAttribute NewAttr = newAttrs.at(0).GetAttributes();
|
||||
const TextAttribute NewAttr = newAttrs[0].GetAttributes();
|
||||
|
||||
// If the existing run was only 1 element...
|
||||
// ...and the new color is the same as the old, we don't have to do anything and can exit quick.
|
||||
if (_list.size() == 1 && _list.at(0).GetAttributes() == NewAttr)
|
||||
if (_list.size() == 1 && _list[0].GetAttributes() == NewAttr)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ public:
|
||||
TextAttribute GetAttrByColumn(const size_t column,
|
||||
size_t* const pApplies) const;
|
||||
|
||||
TextAttribute GetAttrByIndex(const size_t index) const;
|
||||
|
||||
size_t GetNumberOfRuns() const noexcept;
|
||||
|
||||
size_t FindAttrIndex(const size_t index,
|
||||
|
||||
@@ -233,7 +233,9 @@ void CharRow::ClearGlyph(const size_t column)
|
||||
// - Note: will throw exception if column is out of bounds
|
||||
const CharRow::reference CharRow::GlyphAt(const size_t column) const
|
||||
{
|
||||
#ifdef DBG
|
||||
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
|
||||
#endif
|
||||
return { const_cast<CharRow&>(*this), column };
|
||||
}
|
||||
|
||||
@@ -246,7 +248,9 @@ const CharRow::reference CharRow::GlyphAt(const size_t column) const
|
||||
// - Note: will throw exception if column is out of bounds
|
||||
CharRow::reference CharRow::GlyphAt(const size_t column)
|
||||
{
|
||||
#ifdef DBG
|
||||
THROW_HR_IF(E_INVALIDARG, column >= _data.size());
|
||||
#endif
|
||||
return { *this, column };
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ CharRowCellReference::operator std::wstring_view() const
|
||||
// - ref to the CharRowCell
|
||||
CharRowCell& CharRowCellReference::_cellData()
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
return _parent._data[_index];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -50,7 +50,7 @@ CharRowCell& CharRowCellReference::_cellData()
|
||||
// - ref to the CharRowCell
|
||||
const CharRowCell& CharRowCellReference::_cellData() const
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
return _parent._data[_index];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -169,42 +169,33 @@ OutputCellIterator::OutputCellIterator(const std::basic_string_view<OutputCell>
|
||||
// - True if the views on dereference are valid. False if it shouldn't be dereferenced.
|
||||
OutputCellIterator::operator bool() const noexcept
|
||||
{
|
||||
try
|
||||
switch (_mode)
|
||||
{
|
||||
switch (_mode)
|
||||
{
|
||||
case Mode::Loose:
|
||||
case Mode::LooseTextOnly:
|
||||
{
|
||||
// In lieu of using start and end, this custom iterator type simply becomes bool false
|
||||
// when we run out of items to iterate over.
|
||||
return _pos < std::get<std::wstring_view>(_run).length();
|
||||
}
|
||||
case Mode::Fill:
|
||||
{
|
||||
if (_fillLimit > 0)
|
||||
{
|
||||
return _pos < _fillLimit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Mode::Cell:
|
||||
{
|
||||
return _pos < std::get<std::basic_string_view<OutputCell>>(_run).length();
|
||||
}
|
||||
case Mode::CharInfo:
|
||||
{
|
||||
return _pos < std::get<std::basic_string_view<CHAR_INFO>>(_run).length();
|
||||
}
|
||||
case Mode::LegacyAttr:
|
||||
{
|
||||
return _pos < std::get<std::wstring_view>(_run).length();
|
||||
}
|
||||
default:
|
||||
FAIL_FAST_HR(E_NOTIMPL);
|
||||
}
|
||||
case Mode::Loose:
|
||||
case Mode::LooseTextOnly: {
|
||||
// In lieu of using start and end, this custom iterator type simply becomes bool false
|
||||
// when we run out of items to iterate over.
|
||||
return _pos < std::get<std::wstring_view>(_run).length();
|
||||
}
|
||||
case Mode::Fill: {
|
||||
if (_fillLimit > 0)
|
||||
{
|
||||
return _pos < _fillLimit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Mode::Cell: {
|
||||
return _pos < std::get<std::basic_string_view<OutputCell>>(_run).length();
|
||||
}
|
||||
case Mode::CharInfo: {
|
||||
return _pos < std::get<std::basic_string_view<CHAR_INFO>>(_run).length();
|
||||
}
|
||||
case Mode::LegacyAttr: {
|
||||
return _pos < std::get<std::wstring_view>(_run).length();
|
||||
}
|
||||
default:
|
||||
FAIL_FAST_HR(E_NOTIMPL);
|
||||
}
|
||||
CATCH_FAIL_FAST();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -218,8 +209,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
|
||||
switch (_mode)
|
||||
{
|
||||
case Mode::Loose:
|
||||
{
|
||||
case Mode::Loose: {
|
||||
if (!_TryMoveTrailing())
|
||||
{
|
||||
// When walking through a text sequence, we need to move forward by the number of wchar_ts consumed in the previous view
|
||||
@@ -232,8 +222,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::LooseTextOnly:
|
||||
{
|
||||
case Mode::LooseTextOnly: {
|
||||
if (!_TryMoveTrailing())
|
||||
{
|
||||
// When walking through a text sequence, we need to move forward by the number of wchar_ts consumed in the previous view
|
||||
@@ -246,8 +235,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::Fill:
|
||||
{
|
||||
case Mode::Fill: {
|
||||
if (!_TryMoveTrailing())
|
||||
{
|
||||
if (_currentView.DbcsAttr().IsTrailing())
|
||||
@@ -269,8 +257,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::Cell:
|
||||
{
|
||||
case Mode::Cell: {
|
||||
// Walk forward by one because cells are assumed to be in the form they needed to be
|
||||
_pos++;
|
||||
if (operator bool())
|
||||
@@ -279,8 +266,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::CharInfo:
|
||||
{
|
||||
case Mode::CharInfo: {
|
||||
// Walk forward by one because charinfos are just the legacy version of cells and prealigned to columns
|
||||
_pos++;
|
||||
if (operator bool())
|
||||
@@ -289,8 +275,7 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Mode::LegacyAttr:
|
||||
{
|
||||
case Mode::LegacyAttr: {
|
||||
// Walk forward by one because color attributes apply cell by cell (no complex text information)
|
||||
_pos++;
|
||||
if (operator bool())
|
||||
|
||||
@@ -160,66 +160,95 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const size_t index, co
|
||||
// If we're given a right-side column limit, use it. Otherwise, the write limit is the final column index available in the char row.
|
||||
const auto finalColumnInRow = limitRight.value_or(_charRow.size() - 1);
|
||||
|
||||
while (it && currentIndex <= finalColumnInRow)
|
||||
if (it)
|
||||
{
|
||||
// Fill the color if the behavior isn't set to keeping the current color.
|
||||
if (it->TextAttrBehavior() != TextAttributeBehavior::Current)
|
||||
// Accumulate usages of the same color so we can spend less time in InsertAttrRuns rewriting it.
|
||||
auto currentColor = it->TextAttr();
|
||||
size_t colorUses = 0;
|
||||
size_t colorStarts = index;
|
||||
|
||||
while (it && currentIndex <= finalColumnInRow)
|
||||
{
|
||||
const TextAttributeRun attrRun{ 1, it->TextAttr() };
|
||||
LOG_IF_FAILED(_attrRow.InsertAttrRuns({ &attrRun, 1 },
|
||||
currentIndex,
|
||||
currentIndex,
|
||||
_charRow.size()));
|
||||
}
|
||||
|
||||
// Fill the text if the behavior isn't set to saying there's only a color stored in this iterator.
|
||||
if (it->TextAttrBehavior() != TextAttributeBehavior::StoredOnly)
|
||||
{
|
||||
const bool fillingLastColumn = currentIndex == finalColumnInRow;
|
||||
|
||||
// TODO: MSFT: 19452170 - We need to ensure when writing any trailing byte that the one to the left
|
||||
// is a matching leading byte. Likewise, if we're writing a leading byte, we need to make sure we still have space in this loop
|
||||
// for the trailing byte coming up before writing it.
|
||||
|
||||
// If we're trying to fill the first cell with a trailing byte, pad it out instead by clearing it.
|
||||
// Don't increment iterator. We'll advance the index and try again with this value on the next round through the loop.
|
||||
if (currentIndex == 0 && it->DbcsAttr().IsTrailing())
|
||||
// Fill the color if the behavior isn't set to keeping the current color.
|
||||
if (it->TextAttrBehavior() != TextAttributeBehavior::Current)
|
||||
{
|
||||
_charRow.ClearCell(currentIndex);
|
||||
// If the color of this cell is the same as the run we're currently on,
|
||||
// just increment the counter.
|
||||
if (currentColor == it->TextAttr())
|
||||
{
|
||||
++colorUses;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, commit this color into the run and save off the new one.
|
||||
const TextAttributeRun run{ colorUses, currentColor };
|
||||
// Now commit the new color runs into the attr row.
|
||||
LOG_IF_FAILED(_attrRow.InsertAttrRuns({ &run, 1 },
|
||||
index,
|
||||
currentIndex - 1,
|
||||
_charRow.size()));
|
||||
currentColor = it->TextAttr();
|
||||
colorUses = 1;
|
||||
colorStarts = currentIndex;
|
||||
}
|
||||
}
|
||||
// If we're trying to fill the last cell with a leading byte, pad it out instead by clearing it.
|
||||
// Don't increment iterator. We'll exit because we couldn't write a lead at the end of a line.
|
||||
else if (fillingLastColumn && it->DbcsAttr().IsLeading())
|
||||
|
||||
// Fill the text if the behavior isn't set to saying there's only a color stored in this iterator.
|
||||
if (it->TextAttrBehavior() != TextAttributeBehavior::StoredOnly)
|
||||
{
|
||||
_charRow.ClearCell(currentIndex);
|
||||
_charRow.SetDoubleBytePadded(true);
|
||||
const bool fillingLastColumn = currentIndex == finalColumnInRow;
|
||||
|
||||
// TODO: MSFT: 19452170 - We need to ensure when writing any trailing byte that the one to the left
|
||||
// is a matching leading byte. Likewise, if we're writing a leading byte, we need to make sure we still have space in this loop
|
||||
// for the trailing byte coming up before writing it.
|
||||
|
||||
// If we're trying to fill the first cell with a trailing byte, pad it out instead by clearing it.
|
||||
// Don't increment iterator. We'll advance the index and try again with this value on the next round through the loop.
|
||||
if (currentIndex == 0 && it->DbcsAttr().IsTrailing())
|
||||
{
|
||||
_charRow.ClearCell(currentIndex);
|
||||
}
|
||||
// If we're trying to fill the last cell with a leading byte, pad it out instead by clearing it.
|
||||
// Don't increment iterator. We'll exit because we couldn't write a lead at the end of a line.
|
||||
else if (fillingLastColumn && it->DbcsAttr().IsLeading())
|
||||
{
|
||||
_charRow.ClearCell(currentIndex);
|
||||
_charRow.SetDoubleBytePadded(true);
|
||||
}
|
||||
// Otherwise, copy the data given and increment the iterator.
|
||||
else
|
||||
{
|
||||
_charRow.DbcsAttrAt(currentIndex) = it->DbcsAttr();
|
||||
_charRow.GlyphAt(currentIndex) = it->Chars();
|
||||
++it;
|
||||
}
|
||||
|
||||
// If we're asked to (un)set the wrap status and we just filled the last column with some text...
|
||||
// NOTE:
|
||||
// - wrap = std::nullopt --> don't change the wrap value
|
||||
// - wrap = true --> we're filling cells as a steam, consider this a wrap
|
||||
// - wrap = false --> we're filling cells as a block, unwrap
|
||||
if (wrap.has_value() && fillingLastColumn)
|
||||
{
|
||||
// set wrap status on the row to parameter's value.
|
||||
_charRow.SetWrapForced(wrap.value());
|
||||
}
|
||||
}
|
||||
// Otherwise, copy the data given and increment the iterator.
|
||||
else
|
||||
{
|
||||
_charRow.DbcsAttrAt(currentIndex) = it->DbcsAttr();
|
||||
_charRow.GlyphAt(currentIndex) = it->Chars();
|
||||
++it;
|
||||
}
|
||||
|
||||
// If we're asked to (un)set the wrap status and we just filled the last column with some text...
|
||||
// NOTE:
|
||||
// - wrap = std::nullopt --> don't change the wrap value
|
||||
// - wrap = true --> we're filling cells as a steam, consider this a wrap
|
||||
// - wrap = false --> we're filling cells as a block, unwrap
|
||||
if (wrap.has_value() && fillingLastColumn)
|
||||
{
|
||||
// set wrap status on the row to parameter's value.
|
||||
_charRow.SetWrapForced(wrap.value());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
// Move to the next cell for the next time through the loop.
|
||||
++currentIndex;
|
||||
}
|
||||
|
||||
// Move to the next cell for the next time through the loop.
|
||||
++currentIndex;
|
||||
// Now commit the final color into the attr row
|
||||
const TextAttributeRun run{ colorUses, currentColor };
|
||||
LOG_IF_FAILED(_attrRow.InsertAttrRuns({ &run, 1 },
|
||||
colorStarts,
|
||||
currentIndex - 1,
|
||||
_charRow.size()));
|
||||
}
|
||||
|
||||
return it;
|
||||
|
||||
@@ -33,13 +33,16 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
|
||||
_cursor{ cursorSize, *this },
|
||||
_storage{},
|
||||
_unicodeStorage{},
|
||||
_renderTarget{ renderTarget }
|
||||
_renderTarget{ renderTarget },
|
||||
_size{}
|
||||
{
|
||||
// initialize ROWs
|
||||
for (size_t i = 0; i < static_cast<size_t>(screenBufferSize.Y); ++i)
|
||||
{
|
||||
_storage.emplace_back(static_cast<SHORT>(i), screenBufferSize.X, _currentAttributes, this);
|
||||
}
|
||||
|
||||
_UpdateSize();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -78,7 +81,7 @@ const ROW& TextBuffer::GetRowByOffset(const size_t index) const
|
||||
|
||||
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
|
||||
const size_t offsetIndex = (_firstRow + index) % totalRows;
|
||||
return _storage.at(offsetIndex);
|
||||
return _storage[offsetIndex];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -94,7 +97,7 @@ ROW& TextBuffer::GetRowByOffset(const size_t index)
|
||||
|
||||
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
|
||||
const size_t offsetIndex = (_firstRow + index) % totalRows;
|
||||
return _storage.at(offsetIndex);
|
||||
return _storage[offsetIndex];
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -652,9 +655,15 @@ const SHORT TextBuffer::GetFirstRowIndex() const noexcept
|
||||
{
|
||||
return _firstRow;
|
||||
}
|
||||
const Viewport TextBuffer::GetSize() const
|
||||
|
||||
const Viewport TextBuffer::GetSize() const noexcept
|
||||
{
|
||||
return Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
|
||||
return _size;
|
||||
}
|
||||
|
||||
void TextBuffer::_UpdateSize()
|
||||
{
|
||||
_size = Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
|
||||
}
|
||||
|
||||
void TextBuffer::_SetFirstRowIndex(const SHORT FirstRowIndex) noexcept
|
||||
@@ -845,6 +854,9 @@ void TextBuffer::Reset()
|
||||
// Also take advantage of the row ID refresh loop to resize the rows in the X dimension
|
||||
// and cleanup the UnicodeStorage characters that might fall outside the resized buffer.
|
||||
_RefreshRowIDs(newSize.X);
|
||||
|
||||
// Update the cached size value
|
||||
_UpdateSize();
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
|
||||
const SHORT GetFirstRowIndex() const noexcept;
|
||||
|
||||
const Microsoft::Console::Types::Viewport GetSize() const;
|
||||
const Microsoft::Console::Types::Viewport GetSize() const noexcept;
|
||||
|
||||
void ScrollRows(const SHORT firstRow, const SHORT size, const SHORT delta);
|
||||
|
||||
@@ -177,6 +177,8 @@ public:
|
||||
std::optional<std::reference_wrapper<PositionInformation>> positionInfo);
|
||||
|
||||
private:
|
||||
void _UpdateSize();
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
std::deque<ROW> _storage;
|
||||
Cursor _cursor;
|
||||
|
||||
|
||||
@@ -383,6 +383,47 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
CATCH_LOG()
|
||||
|
||||
static auto channelpair = til::spsc::channel<wchar_t>(16 * 1024);
|
||||
static ConptyConnection* obj = nullptr;
|
||||
static void terminalOutputHandlerMethod()
|
||||
{
|
||||
std::vector<wchar_t> buf(16 * 1024, L'\0');
|
||||
|
||||
while (true)
|
||||
{
|
||||
// OK. So this is going to go all the way down to a winrt::hstring.
|
||||
// "But!", you say, "isn't a `std::wstring_view` like we're creating for the passing
|
||||
// (to avoid a copy) not guaranteed to be null terminated?"
|
||||
// Well, yes, you're right. However, the `winrt::hstring(std::wstring_view)` constuctor
|
||||
// doesn't seem to care about that. It has the full intent of just taking the data pointer
|
||||
// and embedding it inside itself as the hstring reference (instead of copying).
|
||||
// That's a good thing. Except that hstrings have to be null terminated.
|
||||
// So it contains a beautiful check for str[size] != 0 to ensure that the view you gave it
|
||||
// was null terminated and it just flat out `std::terminate`s you if it's not. (You know
|
||||
// instead of doing something like copying it or throwing or documenting any of these facts
|
||||
// in either the header, the constructor, or on MSDN.)
|
||||
|
||||
auto [count, ok] = channelpair.second.pop_n(til::spsc::block_initially, buf.data(), buf.size() - 1);
|
||||
if (!ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure the end of it is null or risk the wrath of `winrt::hstring` when we hit the
|
||||
// WinRT event callback on the way out of this module (see above).
|
||||
buf[count] = '\0';
|
||||
|
||||
obj->_DoOutputThreadWork(std::wstring_view{ buf.data(), count });
|
||||
}
|
||||
}
|
||||
|
||||
static std::thread th(terminalOutputHandlerMethod);
|
||||
|
||||
void ConptyConnection::_DoOutputThreadWork(std::wstring_view str)
|
||||
{
|
||||
_TerminalOutputHandlers(str);
|
||||
}
|
||||
|
||||
DWORD ConptyConnection::_OutputThread()
|
||||
{
|
||||
// Keep us alive until the output thread terminates; the destructor
|
||||
@@ -445,7 +486,13 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
}
|
||||
|
||||
// Pass the output to our registered event handlers
|
||||
_TerminalOutputHandlers(_u16Str);
|
||||
if (!obj)
|
||||
{
|
||||
obj = this;
|
||||
}
|
||||
channelpair.first.push_n(_u16Str.data(), _u16Str.size());
|
||||
|
||||
//_TerminalOutputHandlers(_u16Str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -66,6 +66,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
std::array<char, 4096> _buffer;
|
||||
|
||||
DWORD _OutputThread();
|
||||
|
||||
public:
|
||||
void _DoOutputThreadWork(std::wstring_view str);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ ThrottledFunc<>::ThrottledFunc(ThrottledFunc::Func func, TimeSpan delay, CoreDis
|
||||
// - <none>
|
||||
void ThrottledFunc<>::Run()
|
||||
{
|
||||
if (_isRunPending.test_and_set())
|
||||
if (_isRunPending.test_and_set(std::memory_order_acquire))
|
||||
{
|
||||
// already pending
|
||||
return;
|
||||
@@ -44,7 +44,7 @@ void ThrottledFunc<>::Run()
|
||||
if (auto self{ weakThis.lock() })
|
||||
{
|
||||
timer.Stop();
|
||||
self->_isRunPending.clear();
|
||||
self->_isRunPending.clear(std::memory_order_release);
|
||||
self->_func();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1062,10 +1062,10 @@ constexpr unsigned int LOCAL_BUFFER_SIZE = 100;
|
||||
// - S_OK if successful.
|
||||
// - S_OK if we need to wait (check if ppWaiter is not nullptr).
|
||||
// - Or a suitable HRESULT code for math/string/memory failures.
|
||||
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
[[nodiscard]] HRESULT WriteConsoleAImplForReals(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1238,6 +1238,50 @@ constexpr unsigned int LOCAL_BUFFER_SIZE = 100;
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
static auto channelpair = til::spsc::channel<char>(16* 1024);
|
||||
static IConsoleOutputObject* obj = nullptr;
|
||||
static void ioWriteConsoleMethod()
|
||||
{
|
||||
size_t read = 0;
|
||||
std::unique_ptr<IWaitRoutine> wait;
|
||||
|
||||
std::vector<char> buf(16 * 1024, '\0');
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto [count, ok] = channelpair.second.pop_n(til::spsc::block_initially, buf.data(), buf.size());
|
||||
if (!ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_IF_FAILED(WriteConsoleAImplForReals(*obj, std::string_view{ buf.data(), count }, read, wait));
|
||||
}
|
||||
}
|
||||
|
||||
static std::thread th(ioWriteConsoleMethod);
|
||||
|
||||
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
|
||||
const std::string_view buffer,
|
||||
size_t& read,
|
||||
std::unique_ptr<IWaitRoutine>& waiter) noexcept
|
||||
try
|
||||
{
|
||||
read = buffer.size();
|
||||
waiter.reset();
|
||||
|
||||
if (!obj)
|
||||
{
|
||||
obj = &context;
|
||||
}
|
||||
|
||||
channelpair.first.push_n(buffer.data(), buffer.size());
|
||||
|
||||
return S_OK;
|
||||
//return WriteConsoleAImplForReals(context, buffer, read, waiter);
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
// Routine Description:
|
||||
// - Writes Unicode formatted data into the given console output object.
|
||||
// - NOTE: This may be blocked for various console states and will return a wait context pointer if necessary.
|
||||
|
||||
@@ -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"
|
||||
{
|
||||
|
||||
603
src/inc/til/spsc.h
Normal file
603
src/inc/til/spsc.h
Normal file
@@ -0,0 +1,603 @@
|
||||
// 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
|
||||
|
||||
namespace til::spsc // Terminal Implementation Library. Also: "Today I Learned"
|
||||
{
|
||||
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
|
||||
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) noexcept
|
||||
{
|
||||
#if _TIL_SPSC_DETAIL_POSITION_IMPL_WIN
|
||||
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
|
||||
{
|
||||
size_type begin;
|
||||
size_type end;
|
||||
size_type next;
|
||||
bool alive;
|
||||
|
||||
constexpr acquisition(size_type begin, size_type end, size_type next, bool alive) :
|
||||
begin(begin),
|
||||
end(end),
|
||||
next(next),
|
||||
alive(alive)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// 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.
|
||||
// The producer's writable range is [_producer, _consumer) and the consumer's readable is [_consumer, _producer).
|
||||
// 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".
|
||||
// The arguments are correspondingly flipped for the consumer.
|
||||
//
|
||||
// While the producer is logically always ahead of the consumer, due to the underlying
|
||||
// buffer being a ring buffer, the producer's position might be smaller than the consumer's
|
||||
// position, if both are calculated modulo the buffer's capacity, as we're doing here.
|
||||
// As such the logic range [_producer, _consumer) might actually be the two ranges
|
||||
// [_producer, _capacity) & [0, _consumer)
|
||||
// if _producer > _consumer, modulo _capacity, since the range wraps around the end of the ring buffer.
|
||||
//
|
||||
// The producer cannot write more values ahead of the consumer than the buffer's capacity.
|
||||
// Inversely the consumer must wait until the producer has written at least one value ahead.
|
||||
// In order to implement the first requirement the positions will flip their "revolution_flag" bit each other
|
||||
// revolution around the ring buffer. If the positions are identical, except for their "revolution_flag"
|
||||
// value it signals to the producer that it's ahead by one "revolution", or capacity-many values.
|
||||
// The second requirement can similarly be detected if the two positions are identical including this bit.
|
||||
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
|
||||
// Only the producer's waitMask is != 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" };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr details::block_initially_policy block_initially{};
|
||||
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));
|
||||
}
|
||||
|
||||
// move_n moves count items from the input iterator in into the queue.
|
||||
// The resulting iterator 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);
|
||||
}
|
||||
|
||||
// move_n moves count items from the input iterator in into the queue.
|
||||
// The resulting iterator 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 no items are available and the producer is gone.
|
||||
// The call blocks until either of these events occur.
|
||||
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 writes up to count items into the given output iterator out.
|
||||
// The resulting iterator is returned as the first pair field.
|
||||
// The second pair field will be false if no items are available and the producer 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) };
|
||||
}
|
||||
}
|
||||
@@ -29,10 +29,10 @@ Renderer::Renderer(IRenderData* pData,
|
||||
_pData(pData),
|
||||
_pThread{ std::move(thread) },
|
||||
_destructing{ false },
|
||||
_clusterBuffer{}
|
||||
_text{},
|
||||
_clusterMap{},
|
||||
_viewport{Viewport::Empty()}
|
||||
{
|
||||
_srViewportPrevious = { 0 };
|
||||
|
||||
for (size_t i = 0; i < cEngines; i++)
|
||||
{
|
||||
IRenderEngine* engine = rgpEngines[i];
|
||||
@@ -208,15 +208,16 @@ 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))
|
||||
{
|
||||
view.ConvertToOrigin(&srUpdateRegion);
|
||||
std::for_each(_rgpEngines.begin(), _rgpEngines.end(), [&](IRenderEngine* const pEngine) {
|
||||
for (auto pEngine : _rgpEngines)
|
||||
{
|
||||
LOG_IF_FAILED(pEngine->Invalidate(&srUpdateRegion));
|
||||
});
|
||||
}
|
||||
|
||||
_NotifyPaintFrame();
|
||||
}
|
||||
@@ -357,7 +358,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,13 +370,13 @@ 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
|
||||
// (instead of growing naturally) or shrink down to reduce usage as appropriate.
|
||||
const size_t lineLength = gsl::narrow_cast<size_t>(til::rectangle{ srNewViewport }.width());
|
||||
til::manage_vector(_clusterBuffer, lineLength, _shrinkThreshold);
|
||||
til::manage_vector(_clusterMap, lineLength, _shrinkThreshold);
|
||||
|
||||
if (coordDelta.X != 0 || coordDelta.Y != 0)
|
||||
{
|
||||
@@ -654,7 +655,8 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
|
||||
const auto screenLine = Viewport::Offset(bufferLine, -view.Origin());
|
||||
|
||||
// Retrieve the cell information iterator limited to just this line we want to redraw.
|
||||
auto it = buffer.GetCellDataAt(bufferLine.Origin(), bufferLine);
|
||||
auto& r = buffer.GetRowByOffset(bufferLine.Origin().Y);
|
||||
//auto it = buffer.GetCellDataAt(bufferLine.Origin(), bufferLine);
|
||||
|
||||
// Calculate if two things are true:
|
||||
// 1. this row wrapped
|
||||
@@ -664,27 +666,30 @@ void Renderer::_PaintBufferOutput(_In_ IRenderEngine* const pEngine)
|
||||
(bufferLine.RightExclusive() == buffer.GetSize().Width());
|
||||
|
||||
// Ask the helper to paint through this specific line.
|
||||
_PaintBufferOutputHelper(pEngine, it, screenLine.Origin(), lineWrapped);
|
||||
_PaintBufferOutputHelper(pEngine, r, bufferLine.RightExclusive(), screenLine.Origin(), lineWrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool _IsAllSpaces(const std::wstring_view v)
|
||||
{
|
||||
// first non-space char is not found (is npos)
|
||||
return v.find_first_not_of(L" ") == decltype(v)::npos;
|
||||
}
|
||||
//static bool _IsAllSpaces(const std::wstring_view v)
|
||||
//{
|
||||
// // first non-space char is not found (is npos)
|
||||
// return v.find_first_not_of(L" ") == decltype(v)::npos;
|
||||
//}
|
||||
|
||||
void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
TextBufferCellIterator it,
|
||||
const ROW& r,
|
||||
const SHORT limitRight,
|
||||
const COORD target,
|
||||
const bool lineWrapped)
|
||||
{
|
||||
auto globalInvert{ _pData->IsScreenReversed() };
|
||||
/*auto globalInvert{ _pData->IsScreenReversed() };*/
|
||||
|
||||
SHORT pos = target.X;
|
||||
|
||||
// If we have valid data, let's figure out how to draw it.
|
||||
if (it)
|
||||
if (pos < limitRight)
|
||||
{
|
||||
// TODO: MSFT: 20961091 - This is a perf issue. Instead of rebuilding this and allocing memory to hold the reinterpretation,
|
||||
// we should have an iterator/view adapter for the rendering.
|
||||
@@ -693,13 +698,18 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
size_t cols = 0;
|
||||
|
||||
// Retrieve the first color.
|
||||
auto color = it->TextAttr();
|
||||
|
||||
size_t colorApplies = 0;
|
||||
const auto& charRow = r.GetCharRow();
|
||||
const auto& attrRow = r.GetAttrRow();
|
||||
auto colorIdx = attrRow.FindAttrIndex(pos, &colorApplies);
|
||||
auto color = attrRow.GetAttrByIndex(colorIdx);
|
||||
|
||||
// And hold the point where we should start drawing.
|
||||
auto screenPoint = target;
|
||||
|
||||
// This outer loop will continue until we reach the end of the text we are trying to draw.
|
||||
while (it)
|
||||
while (pos < limitRight)
|
||||
{
|
||||
// Hold onto the current run color right here for the length of the outer loop.
|
||||
// We'll be changing the persistent one as we run through the inner loops to detect
|
||||
@@ -716,11 +726,12 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
|
||||
// Hold onto the start of this run iterator and the target location where we started
|
||||
// in case we need to do some special work to paint the line drawing characters.
|
||||
const auto currentRunItStart = it;
|
||||
const auto currentRunItStart = pos;
|
||||
const auto currentRunTargetStart = screenPoint;
|
||||
|
||||
// Ensure that our cluster vector is clear.
|
||||
_clusterBuffer.clear();
|
||||
_text.clear();
|
||||
_clusterMap.clear();
|
||||
|
||||
// Reset our flag to know when we're in the special circumstance
|
||||
// of attempting to draw only the right-half of a two-column character
|
||||
@@ -734,25 +745,32 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// When the color changes, it will save the new color off and break.
|
||||
do
|
||||
{
|
||||
if (color != it->TextAttr())
|
||||
if (colorApplies <= 0)
|
||||
{
|
||||
auto newAttr{ it->TextAttr() };
|
||||
// foreground doesn't matter for runs of spaces (!)
|
||||
// if we trick it . . . we call Paint far fewer times for cmatrix
|
||||
if (!_IsAllSpaces(it->Chars()) || !newAttr.HasIdenticalVisualRepresentationForBlankSpace(color, globalInvert))
|
||||
{
|
||||
color = newAttr;
|
||||
break; // vend this run
|
||||
}
|
||||
colorIdx = attrRow.FindAttrIndex(pos, &colorApplies);
|
||||
color = attrRow.GetAttrByIndex(colorIdx);
|
||||
break;
|
||||
|
||||
//auto newAttr{ it->TextAttr() };
|
||||
//// foreground doesn't matter for runs of spaces (!)
|
||||
//// if we trick it . . . we call Paint far fewer times for cmatrix
|
||||
//if (!_IsAllSpaces(it->Chars()) || !newAttr.HasIdenticalVisualRepresentationForBlankSpace(color, globalInvert))
|
||||
//{
|
||||
// color = newAttr;
|
||||
// break; // vend this run
|
||||
//}
|
||||
}
|
||||
|
||||
// Walk through the text data and turn it into rendering clusters.
|
||||
// Keep the columnCount as we go to improve performance over digging it out of the vector at the end.
|
||||
size_t columnCount = 0;
|
||||
|
||||
const auto dbcsAttr = charRow.DbcsAttrAt(pos);
|
||||
const auto chars = (std::wstring_view)charRow.GlyphAt(pos);
|
||||
|
||||
// If we're on the first cluster to be added and it's marked as "trailing"
|
||||
// (a.k.a. the right half of a two column character), then we need some special handling.
|
||||
if (_clusterBuffer.empty() && it->DbcsAttr().IsTrailing())
|
||||
if (_text.empty() && dbcsAttr.IsTrailing())
|
||||
{
|
||||
// If we have room to move to the left to start drawing...
|
||||
if (screenPoint.X > 0)
|
||||
@@ -762,8 +780,12 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// And tell the next function to trim off the left half of it.
|
||||
trimLeft = true;
|
||||
// And add one to the number of columns we expect it to take as we insert it.
|
||||
columnCount = it->Columns() + 1;
|
||||
_clusterBuffer.emplace_back(it->Chars(), columnCount);
|
||||
columnCount = 2;
|
||||
//columnCount = it->Columns() + 1;
|
||||
_text.append(chars);
|
||||
_clusterMap.push_back(2);
|
||||
_clusterMap.push_back(0);
|
||||
//_clusterBuffer.emplace_back(chars, columnCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -775,8 +797,14 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// Otherwise if it's not a special case, just insert it as is.
|
||||
else
|
||||
{
|
||||
columnCount = it->Columns();
|
||||
_clusterBuffer.emplace_back(it->Chars(), columnCount);
|
||||
columnCount = dbcsAttr.IsLeading() ? 2 : 1;
|
||||
_text.append(chars);
|
||||
_clusterMap.push_back((UINT16)columnCount);
|
||||
if (columnCount > 1)
|
||||
{
|
||||
_clusterMap.push_back(0);
|
||||
}
|
||||
//_clusterBuffer.emplace_back(chars, columnCount);
|
||||
}
|
||||
|
||||
if (columnCount > 1)
|
||||
@@ -785,13 +813,15 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
}
|
||||
|
||||
// Advance the cluster and column counts.
|
||||
it += columnCount > 0 ? columnCount : 1; // prevent infinite loop for no visible columns
|
||||
const auto delta = (SHORT)(columnCount > 0 ? columnCount : 1); // prevent infinite loop for no visible columns
|
||||
pos += delta;
|
||||
colorApplies -= delta;
|
||||
cols += columnCount;
|
||||
|
||||
} while (it);
|
||||
} while (pos < limitRight);
|
||||
|
||||
// Do the painting.
|
||||
THROW_IF_FAILED(pEngine->PaintBufferLine({ _clusterBuffer.data(), _clusterBuffer.size() }, screenPoint, trimLeft, lineWrapped));
|
||||
THROW_IF_FAILED(pEngine->PaintBufferLine(_text, { _clusterMap.data(), _clusterMap.size() }, screenPoint, trimLeft, lineWrapped));
|
||||
|
||||
// If we're allowed to do grid drawing, draw that now too (since it will be coupled with the color data)
|
||||
// We're only allowed to draw the grid lines under certain circumstances.
|
||||
@@ -816,7 +846,7 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// Do that in the future if some WPR trace points you to this spot as super bad.
|
||||
for (auto colsPainted = 0u; colsPainted < cols; ++colsPainted, ++lineIt, ++lineTarget.X)
|
||||
{
|
||||
auto lines = lineIt->TextAttr();
|
||||
auto lines = attrRow.GetAttrByColumn(lineIt);
|
||||
_PaintBufferOutputGridLineHelper(pEngine, lines, 1, lineTarget);
|
||||
}
|
||||
}
|
||||
@@ -1013,7 +1043,7 @@ void Renderer::_PaintOverlay(IRenderEngine& engine,
|
||||
|
||||
auto it = overlay.buffer.GetCellLineDataAt(source);
|
||||
|
||||
_PaintBufferOutputHelper(&engine, it, target, false);
|
||||
//_PaintBufferOutputHelper(&engine, it, target, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,10 +99,16 @@ namespace Microsoft::Console::Render
|
||||
void _PaintBufferOutput(_In_ IRenderEngine* const pEngine);
|
||||
|
||||
void _PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
TextBufferCellIterator it,
|
||||
const ROW& r,
|
||||
const SHORT limitRight,
|
||||
const COORD target,
|
||||
const bool lineWrapped);
|
||||
|
||||
//void _PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
|
||||
// TextBufferCellIterator it,
|
||||
// const COORD target,
|
||||
// const bool lineWrapped);
|
||||
|
||||
static IRenderEngine::GridLines s_GetGridlines(const TextAttribute& textAttribute) noexcept;
|
||||
|
||||
void _PaintBufferOutputGridLineHelper(_In_ IRenderEngine* const pEngine,
|
||||
@@ -120,10 +126,12 @@ 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;
|
||||
std::wstring _text;
|
||||
std::vector<UINT16> _clusterMap;
|
||||
//std::vector<Cluster> _clusterBuffer;
|
||||
|
||||
std::vector<SMALL_RECT> _GetSelectionRects() const;
|
||||
void _ScrollPreviousSelection(const til::point delta);
|
||||
|
||||
@@ -162,17 +162,17 @@ DWORD WINAPI RenderThread::_ThreadProc()
|
||||
{
|
||||
WaitForSingleObject(_hPaintEnabledEvent, INFINITE);
|
||||
|
||||
if (!_fNextFrameRequested.exchange(false))
|
||||
if (!_fNextFrameRequested.exchange(false, std::memory_order_acq_rel))
|
||||
{
|
||||
// <--
|
||||
// If `NotifyPaint` is called at this point, then it will not
|
||||
// set the event because `_fWaiting` is not `true` yet so we have
|
||||
// to check again below.
|
||||
|
||||
_fWaiting.store(true);
|
||||
_fWaiting.store(true, std::memory_order_release);
|
||||
|
||||
// check again now (see comment above)
|
||||
if (!_fNextFrameRequested.exchange(false))
|
||||
if (!_fNextFrameRequested.exchange(false, std::memory_order_acq_rel))
|
||||
{
|
||||
// Wait until a next frame is requested.
|
||||
WaitForSingleObject(_hEvent, INFINITE);
|
||||
@@ -193,7 +193,7 @@ DWORD WINAPI RenderThread::_ThreadProc()
|
||||
// expensive operation, we should reset the event to not render
|
||||
// again if nothing changed.
|
||||
|
||||
_fWaiting.store(false);
|
||||
_fWaiting.store(false, std::memory_order_release);
|
||||
|
||||
// see comment above
|
||||
ResetEvent(_hEvent);
|
||||
@@ -218,13 +218,13 @@ DWORD WINAPI RenderThread::_ThreadProc()
|
||||
|
||||
void RenderThread::NotifyPaint()
|
||||
{
|
||||
if (_fWaiting.load())
|
||||
if (_fWaiting.load(std::memory_order_acquire))
|
||||
{
|
||||
SetEvent(_hEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fNextFrameRequested.store(true);
|
||||
_fNextFrameRequested.store(true, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,25 +78,27 @@ CATCH_RETURN()
|
||||
// - clusters - From the backing buffer, the text to be displayed clustered by the columns it should consume.
|
||||
// Return Value:
|
||||
// - S_OK or suitable memory management issue.
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::AppendClusters(const std::basic_string_view<::Microsoft::Console::Render::Cluster> clusters)
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE CustomTextLayout::AppendClusters(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap)
|
||||
try
|
||||
{
|
||||
_textClusterColumns.reserve(_textClusterColumns.size() + clusters.size());
|
||||
_text.append(text);
|
||||
_textClusterColumns.insert(_textClusterColumns.end(), clusterMap.cbegin(), clusterMap.cend());
|
||||
|
||||
for (const auto& cluster : clusters)
|
||||
{
|
||||
const auto cols = gsl::narrow<UINT16>(cluster.GetColumns());
|
||||
const auto text = cluster.GetText();
|
||||
//for (const auto& cluster : clusters)
|
||||
//{
|
||||
// const auto cols = gsl::narrow<UINT16>(cluster.GetColumns());
|
||||
// const auto text = cluster.GetText();
|
||||
|
||||
// Push back the number of columns for this bit of text.
|
||||
_textClusterColumns.push_back(cols);
|
||||
// // Push back the number of columns for this bit of text.
|
||||
// _textClusterColumns.push_back(cols);
|
||||
|
||||
// If there is more than one text character here, push 0s for the rest of the columns
|
||||
// of the text run.
|
||||
_textClusterColumns.resize(_textClusterColumns.size() + base::ClampSub(text.size(), 1u), gsl::narrow_cast<UINT16>(0u));
|
||||
// // If there is more than one text character here, push 0s for the rest of the columns
|
||||
// // of the text run.
|
||||
// _textClusterColumns.resize(_textClusterColumns.size() + base::ClampSub(text.size(), 1u), gsl::narrow_cast<UINT16>(0u));
|
||||
|
||||
_text += text;
|
||||
}
|
||||
// _text += text;
|
||||
//}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ namespace Microsoft::Console::Render
|
||||
size_t const width,
|
||||
IBoxDrawingEffect* const boxEffect);
|
||||
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE AppendClusters(const std::basic_string_view<::Microsoft::Console::Render::Cluster> clusters);
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE AppendClusters(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap);
|
||||
|
||||
[[nodiscard]] HRESULT STDMETHODCALLTYPE Reset() noexcept;
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ DxEngine::DxEngine() :
|
||||
_invalidateFullRows{ true },
|
||||
_invalidMap{},
|
||||
_invalidScroll{},
|
||||
_allInvalid{ false },
|
||||
_firstFrame{ true },
|
||||
_presentParams{ 0 },
|
||||
_presentReady{ false },
|
||||
@@ -847,6 +848,11 @@ void DxEngine::_InvalidateRectangle(const til::rectangle& rc)
|
||||
_invalidMap.set(invalidate);
|
||||
}
|
||||
|
||||
bool DxEngine::_IsAllInvalid() const noexcept
|
||||
{
|
||||
return std::llabs(_invalidScroll.y()) >= _invalidMap.size().height();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Invalidates a rectangle described in characters
|
||||
// Arguments:
|
||||
@@ -858,7 +864,10 @@ try
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, psrRegion);
|
||||
|
||||
_InvalidateRectangle(Viewport::FromExclusive(*psrRegion).ToInclusive());
|
||||
if (!_allInvalid)
|
||||
{
|
||||
_InvalidateRectangle(Viewport::FromExclusive(*psrRegion).ToInclusive());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -875,7 +884,10 @@ try
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, pcoordCursor);
|
||||
|
||||
_InvalidateRectangle(til::rectangle{ *pcoordCursor, til::size{ 1, 1 } });
|
||||
if (!_allInvalid)
|
||||
{
|
||||
/*_InvalidateRectangle(til::rectangle{ *pcoordCursor, til::size{ 1, 1 } });*/
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -892,9 +904,12 @@ try
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, prcDirtyClient);
|
||||
|
||||
// Dirty client is in pixels. Use divide specialization against glyph factor to make conversion
|
||||
// to cells.
|
||||
_InvalidateRectangle(til::rectangle{ *prcDirtyClient }.scale_down(_glyphCell));
|
||||
if (!_allInvalid)
|
||||
{
|
||||
// Dirty client is in pixels. Use divide specialization against glyph factor to make conversion
|
||||
// to cells.
|
||||
_InvalidateRectangle(til::rectangle{ *prcDirtyClient }.scale_down(_glyphCell));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -908,9 +923,12 @@ CATCH_RETURN();
|
||||
// - S_OK
|
||||
[[nodiscard]] HRESULT DxEngine::InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept
|
||||
{
|
||||
for (const auto& rect : rectangles)
|
||||
if (!_allInvalid)
|
||||
{
|
||||
RETURN_IF_FAILED(Invalidate(&rect));
|
||||
for (const auto& rect : rectangles)
|
||||
{
|
||||
RETURN_IF_FAILED(Invalidate(&rect));
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -930,11 +948,15 @@ try
|
||||
|
||||
const til::point deltaCells{ *pcoordDelta };
|
||||
|
||||
if (deltaCells != til::point{ 0, 0 })
|
||||
if (!_allInvalid)
|
||||
{
|
||||
// Shift the contents of the map and fill in revealed area.
|
||||
_invalidMap.translate(deltaCells, true);
|
||||
_invalidScroll += deltaCells;
|
||||
if (deltaCells != til::point{ 0, 0 })
|
||||
{
|
||||
// Shift the contents of the map and fill in revealed area.
|
||||
_invalidMap.translate(deltaCells, true);
|
||||
_invalidScroll += deltaCells;
|
||||
_allInvalid = _IsAllInvalid();
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
@@ -951,6 +973,7 @@ CATCH_RETURN();
|
||||
try
|
||||
{
|
||||
_invalidMap.set_all();
|
||||
_allInvalid = true;
|
||||
|
||||
// Since everything is invalidated here, mark this as a "first frame", so
|
||||
// that we won't use incremental drawing on it. The caller of this intended
|
||||
@@ -1209,6 +1232,7 @@ try
|
||||
}
|
||||
|
||||
_invalidMap.reset_all();
|
||||
_allInvalid = false;
|
||||
|
||||
_invalidScroll = {};
|
||||
|
||||
@@ -1419,7 +1443,8 @@ CATCH_RETURN()
|
||||
// - fTrimLeft - Whether or not to trim off the left half of a double wide character
|
||||
// Return Value:
|
||||
// - S_OK or relevant DirectX error
|
||||
[[nodiscard]] HRESULT DxEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT DxEngine::PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
COORD const coord,
|
||||
const bool /*trimLeft*/,
|
||||
const bool /*lineWrapped*/) noexcept
|
||||
@@ -1430,7 +1455,7 @@ try
|
||||
|
||||
// Create the text layout
|
||||
RETURN_IF_FAILED(_customLayout->Reset());
|
||||
RETURN_IF_FAILED(_customLayout->AppendClusters(clusters));
|
||||
RETURN_IF_FAILED(_customLayout->AppendClusters(text, clusterMap));
|
||||
|
||||
// Layout then render the text
|
||||
RETURN_IF_FAILED(_customLayout->Draw(_drawingContext.get(), _customRenderer.Get(), origin.x, origin.y));
|
||||
@@ -1819,10 +1844,12 @@ try
|
||||
{
|
||||
RETURN_HR_IF_NULL(E_INVALIDARG, pResult);
|
||||
|
||||
const Cluster cluster(glyph, 0); // columns don't matter, we're doing analysis not layout.
|
||||
//const Cluster cluster(glyph, 0); // columns don't matter, we're doing analysis not layout.
|
||||
|
||||
UINT16 col = 0;
|
||||
|
||||
RETURN_IF_FAILED(_customLayout->Reset());
|
||||
RETURN_IF_FAILED(_customLayout->AppendClusters({ &cluster, 1 }));
|
||||
RETURN_IF_FAILED(_customLayout->AppendClusters(glyph, { &col, 1 }));
|
||||
|
||||
UINT32 columns = 0;
|
||||
RETURN_IF_FAILED(_customLayout->GetColumns(&columns));
|
||||
|
||||
@@ -86,7 +86,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
COORD const coord,
|
||||
bool const fTrimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
@@ -157,6 +158,7 @@ namespace Microsoft::Console::Render
|
||||
bool _invalidateFullRows;
|
||||
til::bitmap _invalidMap;
|
||||
til::point _invalidScroll;
|
||||
bool _allInvalid;
|
||||
|
||||
bool _presentReady;
|
||||
std::vector<RECT> _presentDirty;
|
||||
@@ -271,6 +273,7 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] til::size _GetClientSize() const;
|
||||
|
||||
void _InvalidateRectangle(const til::rectangle& rc);
|
||||
bool _IsAllInvalid() const noexcept;
|
||||
|
||||
[[nodiscard]] D2D1_COLOR_F _ColorFFromColorRef(const COLORREF color) noexcept;
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT ScrollFrame() noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool trimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
|
||||
@@ -284,14 +284,15 @@ using namespace Microsoft::Console::Render;
|
||||
// See: Win7: 390673, 447839 and then superseded by http://osgvsowi/638274 when FE/non-FE rendering condensed.
|
||||
//#define CONSOLE_EXTTEXTOUT_FLAGS ETO_OPAQUE | ETO_CLIPPED
|
||||
//#define MAX_POLY_LINES 80
|
||||
[[nodiscard]] HRESULT GdiEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT GdiEngine::PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool trimLeft,
|
||||
const bool /*lineWrapped*/) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto cchLine = clusters.size();
|
||||
const auto cchLine = text.size();
|
||||
|
||||
// Exit early if there are no lines to draw.
|
||||
RETURN_HR_IF(S_OK, 0 == cchLine);
|
||||
@@ -316,12 +317,13 @@ using namespace Microsoft::Console::Render;
|
||||
// Convert data from clusters into the text array and the widths array.
|
||||
for (size_t i = 0; i < cchLine; i++)
|
||||
{
|
||||
const auto& cluster = clusters.at(i);
|
||||
//const auto& cluster = clusters.at(i);
|
||||
|
||||
// Our GDI renderer hasn't and isn't going to handle things above U+FFFF or sequences.
|
||||
// So replace anything complicated with a replacement character for drawing purposes.
|
||||
pwsPoly[i] = cluster.GetTextAsSingle();
|
||||
rgdxPoly[i] = gsl::narrow<int>(cluster.GetColumns()) * coordFontSize.X;
|
||||
pwsPoly[i] = text[i];
|
||||
//cluster.GetTextAsSingle();
|
||||
rgdxPoly[i] = gsl::narrow<int>(clusterMap[i]) * coordFontSize.X;
|
||||
cchCharWidths += rgdxPoly[i];
|
||||
}
|
||||
|
||||
@@ -365,7 +367,7 @@ using namespace Microsoft::Console::Render;
|
||||
}
|
||||
|
||||
pPolyTextLine->lpstr = pwsPoly.release();
|
||||
pPolyTextLine->n = gsl::narrow<UINT>(clusters.size());
|
||||
pPolyTextLine->n = gsl::narrow<UINT>(text.size());
|
||||
pPolyTextLine->x = ptDraw.x;
|
||||
pPolyTextLine->y = ptDraw.y;
|
||||
pPolyTextLine->uiFlags = ETO_OPAQUE | ETO_CLIPPED;
|
||||
|
||||
@@ -71,7 +71,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] virtual HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept = 0;
|
||||
|
||||
[[nodiscard]] virtual HRESULT PaintBackground() noexcept = 0;
|
||||
[[nodiscard]] virtual HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] virtual HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool fTrimLeft,
|
||||
const bool lineWrapped) noexcept = 0;
|
||||
|
||||
@@ -305,7 +305,8 @@ CATCH_RETURN();
|
||||
// - fTrimLeft - Whether or not to trim off the left half of a double wide character
|
||||
// Return Value:
|
||||
// - S_FALSE
|
||||
[[nodiscard]] HRESULT UiaEngine::PaintBufferLine(std::basic_string_view<Cluster> const /*clusters*/,
|
||||
[[nodiscard]] HRESULT UiaEngine::PaintBufferLine(std::wstring_view /*text*/,
|
||||
std::basic_string_view<UINT16> /*clusterMap*/,
|
||||
COORD const /*coord*/,
|
||||
const bool /*trimLeft*/,
|
||||
const bool /*lineWrapped*/) noexcept
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
|
||||
|
||||
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
COORD const coord,
|
||||
bool const fTrimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
|
||||
@@ -498,14 +498,15 @@ CATCH_RETURN();
|
||||
// will be false.
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT XtermEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT XtermEngine::PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool /*trimLeft*/,
|
||||
const bool lineWrapped) noexcept
|
||||
{
|
||||
return _fUseAsciiOnly ?
|
||||
VtEngine::_PaintAsciiBufferLine(clusters, coord) :
|
||||
VtEngine::_PaintUtf8BufferLine(clusters, coord, lineWrapped);
|
||||
VtEngine::_PaintAsciiBufferLine(text, clusterMap, coord) :
|
||||
VtEngine::_PaintUtf8BufferLine(text, clusterMap, coord, lineWrapped);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -41,7 +41,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] virtual HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes,
|
||||
const gsl::not_null<IRenderData*> pData,
|
||||
const bool isSettingDefaultBrushes) noexcept override;
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool trimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include "vtrenderer.hpp"
|
||||
#include "../../inc/conattrs.hpp"
|
||||
#include "../../types/inc/convert.hpp"
|
||||
@@ -125,12 +128,13 @@ using namespace Microsoft::Console::Types;
|
||||
// will be false.
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT VtEngine::PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT VtEngine::PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool /*trimLeft*/,
|
||||
const bool /*lineWrapped*/) noexcept
|
||||
{
|
||||
return VtEngine::_PaintAsciiBufferLine(clusters, coord);
|
||||
return VtEngine::_PaintAsciiBufferLine(text, clusterMap, coord);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -327,27 +331,28 @@ using namespace Microsoft::Console::Types;
|
||||
// - coord - character coordinate target to render within viewport
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT VtEngine::_PaintAsciiBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT VtEngine::_PaintAsciiBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
RETURN_IF_FAILED(_MoveCursor(coord));
|
||||
|
||||
std::wstring wstr;
|
||||
wstr.reserve(clusters.size());
|
||||
/*_bufferLine.clear();*/
|
||||
//_bufferLine.reserve(clusters.size());
|
||||
|
||||
short totalWidth = 0;
|
||||
/*short totalWidth = 0;
|
||||
for (const auto& cluster : clusters)
|
||||
{
|
||||
wstr.append(cluster.GetText());
|
||||
_bufferLine.append(cluster.GetText());
|
||||
RETURN_IF_FAILED(ShortAdd(totalWidth, gsl::narrow<short>(cluster.GetColumns()), &totalWidth));
|
||||
}
|
||||
}*/
|
||||
|
||||
RETURN_IF_FAILED(VtEngine::_WriteTerminalAscii(wstr));
|
||||
RETURN_IF_FAILED(VtEngine::_WriteTerminalAscii(text));
|
||||
|
||||
// Update our internal tracker of the cursor's position
|
||||
_lastText.X += totalWidth;
|
||||
_lastText.X += (SHORT)std::accumulate(clusterMap.begin(), clusterMap.end(), 0);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -362,7 +367,8 @@ using namespace Microsoft::Console::Types;
|
||||
// - coord - character coordinate target to render within viewport
|
||||
// Return Value:
|
||||
// - S_OK or suitable HRESULT error from writing pipe.
|
||||
[[nodiscard]] HRESULT VtEngine::_PaintUtf8BufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT VtEngine::_PaintUtf8BufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool lineWrapped) noexcept
|
||||
{
|
||||
@@ -371,21 +377,21 @@ using namespace Microsoft::Console::Types;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
std::wstring unclusteredString;
|
||||
unclusteredString.reserve(clusters.size());
|
||||
short totalWidth = 0;
|
||||
for (const auto& cluster : clusters)
|
||||
/*_bufferLine.clear();
|
||||
_bufferLine.reserve(clusters.size());*/
|
||||
short totalWidth = (SHORT)std::accumulate(clusterMap.begin(), clusterMap.end(), 0);
|
||||
/*for (const auto& cluster : clusters)
|
||||
{
|
||||
unclusteredString.append(cluster.GetText());
|
||||
_bufferLine.append(cluster.GetText());
|
||||
RETURN_IF_FAILED(ShortAdd(totalWidth, static_cast<short>(cluster.GetColumns()), &totalWidth));
|
||||
}
|
||||
const size_t cchLine = unclusteredString.size();
|
||||
}*/
|
||||
const size_t cchLine = text.size();
|
||||
|
||||
bool foundNonspace = false;
|
||||
size_t lastNonSpace = 0;
|
||||
for (size_t i = 0; i < cchLine; i++)
|
||||
{
|
||||
if (unclusteredString.at(i) != L'\x20')
|
||||
if (text.at(i) != L'\x20')
|
||||
{
|
||||
lastNonSpace = i;
|
||||
foundNonspace = true;
|
||||
@@ -479,8 +485,7 @@ using namespace Microsoft::Console::Types;
|
||||
RETURN_IF_FAILED(_MoveCursor(coord));
|
||||
|
||||
// Write the actual text string
|
||||
std::wstring wstr = std::wstring(unclusteredString.data(), cchActual);
|
||||
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8(wstr));
|
||||
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8({ text.data(), cchActual }));
|
||||
|
||||
// GH#4415, GH#5181
|
||||
// If the renderer told us that this was a wrapped line, then mark
|
||||
|
||||
@@ -98,6 +98,28 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
static auto channelpair = til::spsc::channel<char>(16* 1024);
|
||||
static HANDLE obj = nullptr;
|
||||
|
||||
static void vtRenderWriteMethod()
|
||||
{
|
||||
std::vector<char> buf(16 * 1024, '\0');
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto [count, ok] = channelpair.second.pop_n(til::spsc::block_initially, buf.data(), buf.size());
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
WriteFile(obj, buf.data(), static_cast<DWORD>(count), nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static std::thread th(vtRenderWriteMethod);
|
||||
|
||||
[[nodiscard]] HRESULT VtEngine::_Flush() noexcept
|
||||
{
|
||||
#ifdef UNIT_TESTING
|
||||
@@ -108,7 +130,16 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!_pipeBroken)
|
||||
if (!obj)
|
||||
{
|
||||
obj = _hFile.get();
|
||||
}
|
||||
channelpair.first.push_n(_buffer.data(), _buffer.size());
|
||||
_buffer.clear();
|
||||
|
||||
return S_OK;
|
||||
|
||||
/* if (!_pipeBroken)
|
||||
{
|
||||
bool fSuccess = !!WriteFile(_hFile.get(), _buffer.data(), static_cast<DWORD>(_buffer.size()), nullptr, nullptr);
|
||||
_buffer.clear();
|
||||
@@ -122,9 +153,7 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
||||
}
|
||||
return _exitResult;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}*/
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -145,7 +145,7 @@ void RenderTracing::TraceInvalidateScroll(const til::point scroll) const
|
||||
}
|
||||
|
||||
void RenderTracing::TraceStartPaint(const bool quickReturn,
|
||||
const til::bitmap invalidMap,
|
||||
const til::bitmap& invalidMap,
|
||||
const til::rectangle lastViewport,
|
||||
const til::point scrollDelt,
|
||||
const bool cursorMoved,
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
void TraceTriggerCircling(const bool newFrame) const;
|
||||
void TraceInvalidateScroll(const til::point scroll) const;
|
||||
void TraceStartPaint(const bool quickReturn,
|
||||
const til::bitmap invalidMap,
|
||||
const til::bitmap& invalidMap,
|
||||
const til::rectangle lastViewport,
|
||||
const til::point scrollDelta,
|
||||
const bool cursorMoved,
|
||||
|
||||
@@ -61,7 +61,8 @@ namespace Microsoft::Console::Render
|
||||
[[nodiscard]] virtual HRESULT ScrollFrame() noexcept = 0;
|
||||
|
||||
[[nodiscard]] HRESULT PaintBackground() noexcept override;
|
||||
[[nodiscard]] virtual HRESULT PaintBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] virtual HRESULT PaintBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool trimLeft,
|
||||
const bool lineWrapped) noexcept override;
|
||||
@@ -204,11 +205,16 @@ namespace Microsoft::Console::Render
|
||||
|
||||
bool _WillWriteSingleChar() const;
|
||||
|
||||
[[nodiscard]] HRESULT _PaintUtf8BufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
// buffer space for these two functions to build their lines
|
||||
// so they don't have to alloc/free in a tight loop
|
||||
//std::wstring _bufferLine;
|
||||
[[nodiscard]] HRESULT _PaintUtf8BufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord,
|
||||
const bool lineWrapped) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _PaintAsciiBufferLine(std::basic_string_view<Cluster> const clusters,
|
||||
[[nodiscard]] HRESULT _PaintAsciiBufferLine(std::wstring_view text,
|
||||
std::basic_string_view<UINT16> clusterMap,
|
||||
const COORD coord) noexcept;
|
||||
|
||||
[[nodiscard]] HRESULT _WriteTerminalUtf8(const std::wstring_view str) noexcept;
|
||||
|
||||
194
src/til/ut_til/SPSCTests.cpp
Normal file
194
src/til/ut_til/SPSCTests.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
// 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
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPSCTests.cpp" />
|
||||
<ClCompile Include="u8u16convertTests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user