Compare commits

...

37 Commits

Author SHA1 Message Date
Dustin L. Howett
8998d72b11 Migrate spelling-0.0.21 changes from main 2020-04-03 14:52:05 -05:00
Dustin L. Howett
ecc8ebd8d9 Migrate spelling-0.0.19 changes from main 2020-04-03 14:52:05 -05:00
Mike Griese
3495cad437 Starting on working on fixing this bug, but I can't get a minimal repro, so I'm stashing this.
re: #5161
2020-04-03 14:52:05 -05:00
Mike Griese
12f9c827bb Add more comments 2020-04-03 14:50:34 -05:00
Mike Griese
9ea3960ac3 Spellcheck fixes, thanks to @jsoref 2020-04-03 10:23:54 -05:00
Mike Griese
746a1c830b Frick forgot to save 2020-04-03 10:04:31 -05:00
Mike Griese
c39871b4e7 Fix the bug that Dustin reported in the PR 2020-04-03 09:58:44 -05:00
Mike Griese
a1cd2c517a This is the latest testcase dustin found for me 2020-04-02 12:01:50 -05:00
Mike Griese
a939f7e212 Update this test with more info from the discussion thread 2020-04-02 11:28:47 -05:00
Mike Griese
015844b24e finish the test for #5039 2020-04-02 10:52:33 -05:00
Mike Griese
c7e5a45291 This is the test case that's actaully broken in #5039 2020-04-02 09:51:13 -05:00
Mike Griese
1c9a16f80f add a test for #5039 2020-04-01 16:33:36 -05:00
Mike Griese
0cbcf1f02b fix a typo 2020-04-01 16:33:22 -05:00
Mike Griese
b70aacd4be good bot 2020-04-01 15:32:49 -05:00
Mike Griese
8b19fcbc8d Fix this case for @dhowett-msft 2020-04-01 15:23:43 -05:00
Mike Griese
707844db88 add the failing test for the case Dustin described 2020-04-01 15:07:48 -05:00
Mike Griese
d317b8b990 pr nits from carlos 2020-04-01 14:29:27 -05:00
Mike Griese
465f8beea1 Merge branch 'master' into dev/migrie/b/5113-with-miniksas-fix 2020-04-01 14:20:03 -05:00
Mike Griese
ac85d4353d pr nits from dustin 2020-04-01 09:07:42 -05:00
Mike Griese
022b01ae3c Merge branch 'master' into dev/migrie/b/5113-with-miniksas-fix 2020-04-01 08:26:15 -05:00
Mike Griese
436335f0ab Fix the test @miniksa wrote for #5122
It was unhappy with the exact line lengths and this change
2020-03-30 12:17:40 -05:00
Mike Griese
8ecfcecc6a Merge branch 'master' into dev/migrie/b/5113-with-miniksas-fix
# Conflicts:
#	src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp
#	src/host/ut_host/ConptyOutputTests.cpp
#	src/renderer/vt/XtermEngine.cpp
#	src/renderer/vt/math.cpp
2020-03-30 11:08:13 -05:00
Mike Griese
51f060e100 cleanup for review, but I have to wait for #5122 to merge first 2020-03-27 10:41:28 -05:00
Mike Griese
870f05214c Merge remote-tracking branch 'origin/master' into dev/migrie/b/5113-with-miniksas-fix 2020-03-27 10:22:43 -05:00
Mike Griese
2a0cc2001b I'm honestly shocked that this seems to work 2020-03-27 09:58:30 -05:00
Mike Griese
2665b4c2b3 this fixes this test, but maybe the test was always broken? 2020-03-27 09:45:18 -05:00
Mike Griese
cf1145c7ae Add a test for this case
TODO: This proves that the scrolling during a frame with other text
    breaks this scenario. We're going to try and special-case the scrolling
    thing to _only_ when
    * the invalid area is the bottom line, and
    * the line wrapped
    So in that case, we'll be sure that the next text will cause us to move
    the viewport down a line appropriately
    I've got a crazy theory that rendering bottom-up _might_ fix this
2020-03-26 17:04:43 -05:00
Mike Griese
e21101bd13 This all wroks far to shockingly well 2020-03-26 15:04:19 -05:00
Mike Griese
b94cfdb410 This test failure helps explain that this doesn't work
The test fails validating the second wrapped terminal line.

  I think the problem comes from us manually placing the cursor on the last line
  of the buffer. When we write the next 20 'A's, the first one gets written on
  the last cell of the first row, and that's bad.

  I'm going to see if I can't get rid of that call (the MoveCursor in
  PaintCursor) for this case. That seems like the cause of all this mess.
2020-03-26 11:55:05 -05:00
Mike Griese
248d223081 this is a simple test for the case that already worked 2020-03-26 11:37:04 -05:00
Mike Griese
466e8fc654 mysteriously the existing tests all basically pass 2020-03-26 11:14:58 -05:00
Mike Griese
22bdf9b987 This can't possibly be right... can it? 2020-03-26 10:36:57 -05:00
Mike Griese
d42f960949 So this works but I think it will break the EOL backspace test 2020-03-26 10:22:13 -05:00
Mike Griese
f10edc0d95 Merge remote-tracking branch 'origin/dev/miniksa/tmux_draw' into dev/migrie/b/5113-with-miniksas-fix
# Conflicts:
#	src/renderer/vt/XtermEngine.cpp
#	src/renderer/vt/invalidate.cpp
2020-03-26 09:30:25 -05:00
Mike Griese
9ba2c69417 More tracing is always good
(cherry picked from commit d972b5e07a)
2020-03-26 09:13:34 -05:00
Michael Niksa
a543b1ff8a PR feedback applied. Don't bother making string if no one is listening to ETW. Change the scroll member variable to a til::point and math that directly (and add the operators and related tests to til::point). 2020-03-25 16:21:14 -07:00
Michael Niksa
4bbb63ddf6 Add tracing for circling and scrolling operations. Fix improper invalidation within AdjustCursorPosition routine in the subsection about scrolling down at the bottom with a set of margins enabled. 2020-03-25 14:29:37 -07:00
43 changed files with 2825 additions and 481006 deletions

View File

@@ -1,17 +0,0 @@
<details>
<summary>
:pencil2: Contributor please read this
</summary>
* If the items listed above are names, please add them to `.github/actions/spell-check/dictionary/names.txt`.
* If they're APIs, you can add them to a file in `.github/actions/spell-check/dictionary/`.
* If they're just things you're using, please add them to an appropriate file in `.github/actions/spell-check/whitelist/`.
* If you need to use a specific token in one place and it 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.
</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.

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,7 +0,0 @@
mfcribbon
microsoft
microsoftonline
osgvsowi
powershell
tdbuildteamid
visualstudio

View File

@@ -1,61 +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$
^dep/
^doc/reference/UTF8-torture-test\.txt$
^src/interactivity/onecore/BgfxEngine\.
^src/renderer/wddmcon/WddmConRenderer\.
^src/terminal/parser/ft_fuzzer/VTCommandFuzzer\.cpp$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^\.github/actions/spell-check/
^\.gitignore$

View File

@@ -1,7 +0,0 @@
https://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
(?:0[Xx]|U\+|#)[a-f0-9A-FGgRr]{2,}[Uu]?[Ll]?\b
\{[0-9A-FA-F]{8}-(?:[0-9A-FA-F]{4}-){3}[0-9A-FA-F]{12}\}
\d+x\d+Logo
Scro\&ll
# selectionInput.cpp
:\\windows\\syste\b

View File

@@ -1,7 +0,0 @@
The contents of each `.txt` file in this directory are merged together.
* [alphabet](alphabet.txt) is a sample for alphabet related items
* [web](web.txt) is a sample for web/html related items
* [whitelist](whitelist.txt) is the main whitelist -- there is nothing
particularly special about the file name (beyond the extension which is
important).

View File

@@ -1,3 +0,0 @@
http
td
www

15
.github/actions/spelling/README.md vendored Normal file
View 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
View 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>

View File

@@ -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
View 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
View 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

View 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

View File

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

11
.github/actions/spelling/allow/math.txt vendored Normal file
View File

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

View 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

View File

@@ -1,55 +1,91 @@
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
Pham
Rincewind
rprichard
Schoonover
shadertoy
Shomnipotence
simioni
Somuah
sonph
sonpham
stakx
talo
thereses
Walisch
WDX
Wellons
Wirt
Wojciech
zadjii
Zamor
Zamora
zamora
Zoey
zorio
Zverovich

View 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
(['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hex runs
\b[0-9a-fA-F]{16,}\b
# hex in url queries
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
# ssh
(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,}
# PGP
\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b
# GPG keys
\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b
# Well known gpg keys
.well-known/openpgpkey/[\w./]+
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
# integrity
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
# https://www.gnu.org/software/groff/manual/groff.html
# man troff content
\\f[BCIPR]
# '
\\\(aq
# .desktop mime types
^MimeTypes?=.*$
# .desktop localized entries
^[A-Z][a-z]+\[[a-z]+\]=.*$
# Localized .desktop content
Name\[[^\]]+\]=.*
# IServiceProvider
\bI(?=(?:[A-Z][a-z]{2,})+\b)
# crypt
"\$2[ayb]\$.{56}"
# scrypt / argon
\$(?:scrypt|argon\d+[di]*)\$\S+
# Input to GitHub JSON
content: "[-a-zA-Z=;:/0-9+]*="
# Python stringprefix / binaryprefix
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
# Regular expressions for (P|p)assword
\([A-Z]\|[a-z]\)[a-z]+
# JavaScript regular expressions
# javascript test regex
/.*/[gim]*\.test\(
# javascript match regex
\.match\(/[^/\s"]*/[gim]*\s*
# javascript match regex
\.match\(/\\[b].*?/[gim]*\s*\)(?:;|$)
# javascript regex
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
# javascript replace regex
\.replace\(/[^/\s"]*/[gim]*\s*,
# Go regular expressions
regexp?\.MustCompile\(`[^`]*`\)
# sed regular expressions
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
# go install
go install(?:\s+[a-z]+\.[-@\w/.]+)+
# kubernetes pod status lists
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
# kubectl - pods in CrashLoopBackOff
\w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+
# kubernetes object suffix
-[0-9a-f]{10}-\w{5}\s
# posthog secrets
posthog\.init\((['"])phc_[^"',]+\g{-1},
# xcode
# xcodeproject scenes
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
# xcode api botches
customObjectInstantitationMethod
# font awesome classes
\.fa-[-a-z0-9]+
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
## You could manually change `(?i)X...` to use `[Xx]...`
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
# Lorem
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
# French
# This corpus only had capital letters, but you probably want lowercase ones as well.
\b[LN]'+[a-z]{2,}\b
# latex
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
# the negative lookahead here is to allow catching 'templatesz' as a misspelling
# but to otherwise recognize a Windows path with \templates\foo.template or similar:
\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
# ignore long runs of a single character:
\b([A-Za-z])\g{-1}{3,}\b
# Note that the next example is no longer necessary if you are using
# to match a string starting with a `#`, use a character-class:
[#]backwards
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# Compiler flags (Scala)
(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags
#(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (linker)
,-B
# curl arguments
\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# set arguments
\bset(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)*
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
# macOS temp folders
/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/

117
.github/actions/spelling/excludes.txt vendored Normal file
View 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$

View File

@@ -0,0 +1,13 @@
The contents of each `.txt` file in this directory are merged together.
* [alphabet](alphabet.txt) is a sample for alphabet related items
* [web](web.txt) is a sample for web/html related items
* [expect](expect.txt) is the main list of expected items -- there is nothing
particularly special about the file name (beyond the extension which is
important).
These terms are things which temporarily exist in the project, but which
aren't necessarily words.
If something is a word that could come and go, it probably belongs in a
[dictionary](../dictionary/README.md).

View File

@@ -1,27 +1,33 @@
AAAa
AAAAA
AAAAAAAAAAAAA
AAAAAABBBBBBCCC
AAAAABBBBBBCCC
abcd
abcd
abcde
abcdef
ABCDEFG
ABCDEFGH
ABCDEFGHIJ
abcdefghijk
ABCDEFGHIJKLMNO
abcdefghijklmnop
ABCDEFGHIJKLMNOPQRST
abcdefghijklmnopqrstuvwxyz
QQQQQ
QQQQQQQQQ
QQQQQQQQQQ
ABCG
ABE
abf
BBBBB
BBBBBBBB
BBBBBCCC
BBBBCCCCC
BBGGRR
EFG
EFGh
QQQQQQQQQQABCDEFGHIJ
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
qrstuvwxyz
qwerty
QWERTYUIOP
qwertyuiopasdfg
TTTTTTTTTTTTTTTTTTTTTTTTTT
VVVVVVVVVVVVVVVV
yyyy
YYYYYYYDDDDDDDDDDD
ZAAZZ
ZABBZ
ZBAZZ

View File

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

View 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

View 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
View File

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

View File

@@ -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.13-alpha
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
bucket: .github/actions
project: spell-check

134
.github/workflows/spelling2.yml vendored Normal file
View 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 }}

View File

@@ -48,6 +48,11 @@ namespace TerminalCoreUnitTests
};
using namespace TerminalCoreUnitTests;
// Helper for declaring a variable to store a TEST_METHOD_PROPERTY and get it's value from the test metadata
#define INIT_TEST_PROPERTY(type, identifer, description) \
type identifer; \
VERIFY_SUCCEEDED(TestData::TryGetValue(L#identifer, identifer), description);
class TerminalCoreUnitTests::ConptyRoundtripTests final
{
static const SHORT TerminalViewWidth = 80;
@@ -174,6 +179,14 @@ class TerminalCoreUnitTests::ConptyRoundtripTests final
TEST_METHOD(TestResizeHeight);
TEST_METHOD(OutputWrappedLinesAtTopOfBuffer);
TEST_METHOD(OutputWrappedLinesAtBottomOfBuffer);
TEST_METHOD(ScrollWithChangesInMiddle);
TEST_METHOD(DontWrapMoveCursorInSingleFrame);
TEST_METHOD(ClearHostTrickeryTest);
TEST_METHOD(OverstrikeAtBottomOfBuffer);
TEST_METHOD(MarginsWithStatusLine);
TEST_METHOD(ScrollWithMargins);
private:
@@ -950,7 +963,7 @@ void ConptyRoundtripTests::PassthroughClearScrollback()
else
{
// After we hit the bottom of the viewport, the newlines come in
// separated for whatever reason.
// separated by empty writes for whatever reason.
expectedOutput.push_back("\r");
expectedOutput.push_back("\n");
expectedOutput.push_back("");
@@ -1026,8 +1039,7 @@ void ConptyRoundtripTests::PassthroughHardReset()
else
{
// After we hit the bottom of the viewport, the newlines come in
// separated for whatever reason.
// separated by empty writes for whatever reason.
expectedOutput.push_back("\r");
expectedOutput.push_back("\n");
expectedOutput.push_back("");
@@ -1061,6 +1073,225 @@ void ConptyRoundtripTests::PassthroughHardReset()
}
}
void ConptyRoundtripTests::OutputWrappedLinesAtTopOfBuffer()
{
Log::Comment(
L"Case 1: Write a wrapped line right at the start of the buffer, before any circling");
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());
auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
_flushFirstFrame();
const auto wrappedLineLength = TerminalViewWidth + 20;
sm.ProcessString(std::wstring(wrappedLineLength, L'A'));
auto verifyBuffer = [](const TextBuffer& tb) {
VERIFY_IS_TRUE(tb.GetRowByOffset(0).GetCharRow().WasWrapForced());
VERIFY_IS_FALSE(tb.GetRowByOffset(1).GetCharRow().WasWrapForced());
auto iter0 = tb.GetCellDataAt({ 0, 0 });
TestUtils::VerifySpanOfText(L"A", iter0, 0, TerminalViewWidth);
auto iter1 = tb.GetCellDataAt({ 0, 1 });
TestUtils::VerifySpanOfText(L"A", iter1, 0, 20);
auto iter2 = tb.GetCellDataAt({ 20, 1 });
TestUtils::VerifySpanOfText(L" ", iter2, 0, TerminalViewWidth - 20);
};
verifyBuffer(hostTb);
expectedOutput.push_back(std::string(TerminalViewWidth, 'A'));
expectedOutput.push_back(std::string(20, 'A'));
VERIFY_SUCCEEDED(renderer.PaintFrame());
verifyBuffer(termTb);
}
void ConptyRoundtripTests::OutputWrappedLinesAtBottomOfBuffer()
{
Log::Comment(
L"Case 2: Write a wrapped line at the end of the buffer, once the conpty started circling");
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());
auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
_flushFirstFrame();
// First, fill the buffer with contents, so conpty starts circling
const auto hostView = si.GetViewport();
const auto end = 2 * hostView.Height();
for (auto i = 0; i < end; i++)
{
Log::Comment(NoThrowString().Format(L"Writing line %d/%d", i, end));
expectedOutput.push_back("X");
if (i < hostView.BottomInclusive())
{
expectedOutput.push_back("\r\n");
}
else
{
// After we hit the bottom of the viewport, the newlines come in
// separated by empty writes for whatever reason.
expectedOutput.push_back("\r");
expectedOutput.push_back("\n");
expectedOutput.push_back("");
}
hostSm.ProcessString(L"X\n");
VERIFY_SUCCEEDED(renderer.PaintFrame());
}
const auto wrappedLineLength = TerminalViewWidth + 20;
expectedOutput.push_back(std::string(TerminalViewWidth, 'A'));
// TODO GH#5228 might break the "newline & repaint the wrapped char" checks here, that's okay.
expectedOutput.push_back("\r"); // This \r\n is emitted by ScrollFrame to
expectedOutput.push_back("\n"); // add a newline to the bottom of the buffer
expectedOutput.push_back("\x1b[31;80H"); // Move the cursor BACK to the wrapped row
expectedOutput.push_back(std::string(1, 'A')); // Reprint the last character of the wrapped row
expectedOutput.push_back(std::string(20, 'A')); // Print the second line.
hostSm.ProcessString(std::wstring(wrappedLineLength, L'A'));
auto verifyBuffer = [](const TextBuffer& tb, const short wrappedRow) {
VERIFY_IS_TRUE(tb.GetRowByOffset(wrappedRow).GetCharRow().WasWrapForced());
VERIFY_IS_FALSE(tb.GetRowByOffset(wrappedRow + 1).GetCharRow().WasWrapForced());
auto iter0 = tb.GetCellDataAt({ 0, wrappedRow });
TestUtils::VerifySpanOfText(L"A", iter0, 0, TerminalViewWidth);
auto iter1 = tb.GetCellDataAt({ 0, wrappedRow + 1 });
TestUtils::VerifySpanOfText(L"A", iter1, 0, 20);
auto iter2 = tb.GetCellDataAt({ 20, wrappedRow + 1 });
TestUtils::VerifySpanOfText(L" ", iter2, 0, TerminalViewWidth - 20);
};
verifyBuffer(hostTb, hostView.BottomInclusive() - 1);
VERIFY_SUCCEEDED(renderer.PaintFrame());
verifyBuffer(termTb, term->_mutableViewport.BottomInclusive() - 1);
}
void ConptyRoundtripTests::ScrollWithChangesInMiddle()
{
Log::Comment(L"This test checks emitting a wrapped line at the bottom of the"
L" viewport while _also_ emitting other text elsewhere in the same frame. This"
L" output will cause us to scroll the viewport in one frame, but we need to"
L" make sure the wrapped line _stays_ wrapped, and the scrolled text appears in"
L" the right place.");
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());
auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
_flushFirstFrame();
// First, fill the buffer with contents, so conpty starts circling
const auto hostView = si.GetViewport();
const auto end = 2 * hostView.Height();
for (auto i = 0; i < end; i++)
{
Log::Comment(NoThrowString().Format(L"Writing line %d/%d", i, end));
expectedOutput.push_back("X");
if (i < hostView.BottomInclusive())
{
expectedOutput.push_back("\r\n");
}
else
{
// After we hit the bottom of the viewport, the newlines come in
// separated by empty writes for whatever reason.
expectedOutput.push_back("\r");
expectedOutput.push_back("\n");
expectedOutput.push_back("");
}
hostSm.ProcessString(L"X\n");
VERIFY_SUCCEEDED(renderer.PaintFrame());
}
const auto wrappedLineLength = TerminalViewWidth + 20;
// In the Terminal, we're going to expect:
expectedOutput.push_back("\x1b[15;1H"); // Move the cursor to row 14, col 0
expectedOutput.push_back("Y"); // Print a 'Y'
expectedOutput.push_back("\x1b[32;1H"); // Move the cursor to the last row
expectedOutput.push_back(std::string(TerminalViewWidth, 'A')); // Print the first 80 'A's
// This is going to be the end of the first frame - b/c we moved the cursor
// in the middle of the frame, we're going to hide/show the cursor during
// this frame
expectedOutput.push_back("\x1b[?25h"); // hide the cursor
// On the subsequent frame:
// TODO GH#5228 might break the "newline & repaint the wrapped char" checks here, that's okay.
expectedOutput.push_back("\r"); // This \r\n is emitted by ScrollFrame to
expectedOutput.push_back("\n"); // add a newline to the bottom of the buffer
expectedOutput.push_back("\x1b[31;80H"); // Move the cursor BACK to the wrapped row
expectedOutput.push_back(std::string(1, 'A')); // Reprint the last character of the wrapped row
expectedOutput.push_back(std::string(20, 'A')); // Print the second line.
_logConpty = true;
// To the host, we'll do something very similar:
hostSm.ProcessString(L"\x1b"
L"7"); // Save cursor
hostSm.ProcessString(L"\x1b[15;1H"); // Move the cursor to row 14, col 0
hostSm.ProcessString(L"Y"); // Print a 'Y'
hostSm.ProcessString(L"\x1b"
L"8"); // Restore
hostSm.ProcessString(std::wstring(wrappedLineLength, L'A')); // Print 100 'A's
auto verifyBuffer = [](const TextBuffer& tb, const til::rectangle viewport) {
const short wrappedRow = viewport.bottom<short>() - 2;
const short start = viewport.top<short>();
for (short i = start; i < wrappedRow; i++)
{
Log::Comment(NoThrowString().Format(L"Checking row %d", i));
TestUtils::VerifyExpectedString(tb, i == start + 13 ? L"Y" : L"X", { 0, i });
}
VERIFY_IS_TRUE(tb.GetRowByOffset(wrappedRow).GetCharRow().WasWrapForced());
VERIFY_IS_FALSE(tb.GetRowByOffset(wrappedRow + 1).GetCharRow().WasWrapForced());
auto iter0 = tb.GetCellDataAt({ 0, wrappedRow });
TestUtils::VerifySpanOfText(L"A", iter0, 0, TerminalViewWidth);
auto iter1 = tb.GetCellDataAt({ 0, wrappedRow + 1 });
TestUtils::VerifySpanOfText(L"A", iter1, 0, 20);
auto iter2 = tb.GetCellDataAt({ 20, wrappedRow + 1 });
TestUtils::VerifySpanOfText(L" ", iter2, 0, TerminalViewWidth - 20);
};
Log::Comment(NoThrowString().Format(L"Checking the host buffer..."));
verifyBuffer(hostTb, hostView.ToInclusive());
Log::Comment(NoThrowString().Format(L"... Done"));
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(NoThrowString().Format(L"Checking the terminal buffer..."));
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
Log::Comment(NoThrowString().Format(L"... Done"));
}
void ConptyRoundtripTests::ScrollWithMargins()
{
auto& g = ServiceLocator::LocateGlobals();
@@ -1087,6 +1318,7 @@ void ConptyRoundtripTests::ScrollWithMargins()
// The letters represent the data in the TMUX pane.
// The final *** line represents the mode line which we will
// attempt to hold in place and not scroll.
// Note that the last line will contain one '*' less than the width of the window.
Log::Comment(L"Fill host with text pattern by feeding it into VT parser.");
const auto rowsToWrite = initialTermView.Height() - 1;
@@ -1103,7 +1335,7 @@ void ConptyRoundtripTests::ScrollWithMargins()
}
// For the last one, write out the asterisks for the mode line.
for (auto i = 0; i < initialTermView.Width(); ++i)
for (auto i = 0; i < initialTermView.Width() - 1; ++i)
{
hostSm.ProcessCharacter('*');
}
@@ -1127,7 +1359,7 @@ void ConptyRoundtripTests::ScrollWithMargins()
}
// For the last row, verify we have an entire row of asterisks for the mode line.
const std::wstring expectedModeLine(initialTermView.Width(), L'*');
const std::wstring expectedModeLine(initialTermView.Width() - 1, L'*');
const COORD expectedPos{ 0, gsl::narrow<SHORT>(rowsToWrite) };
TestUtils::VerifyExpectedString(tb, expectedModeLine, expectedPos);
};
@@ -1140,13 +1372,8 @@ void ConptyRoundtripTests::ScrollWithMargins()
expectedOutput.push_back("\r\n");
}
{
const std::string expectedString(initialTermView.Width(), '*');
const std::string expectedString(initialTermView.Width() - 1, '*');
expectedOutput.push_back(expectedString);
// Cursor gets reset into bottom right corner as we're writing all the way into that corner.
std::stringstream ss;
ss << "\x1b[" << initialTermView.Height() << ";" << initialTermView.Width() << "H";
expectedOutput.push_back(ss.str());
}
Log::Comment(L"Verify host buffer contains pattern.");
@@ -1257,7 +1484,7 @@ void ConptyRoundtripTests::ScrollWithMargins()
// For the last row, verify we have an entire row of asterisks for the mode line.
{
const std::wstring expectedModeLine(initialTermView.Width(), L'*');
const std::wstring expectedModeLine(initialTermView.Width() - 1, L'*');
const COORD modeLinePos{ 0, gsl::narrow<SHORT>(rowsToWrite) };
TestUtils::VerifyExpectedString(tb, expectedModeLine, modeLinePos);
}
@@ -1279,8 +1506,9 @@ void ConptyRoundtripTests::ScrollWithMargins()
expectedOutput.push_back("\r\n");
}
{
const std::string expectedString(initialTermView.Width(), '*');
expectedOutput.push_back(expectedString);
const std::string expectedString(initialTermView.Width() - 1, '*');
// There will be one extra blank space at the end of the line, because the
expectedOutput.push_back(expectedString + " ");
}
{
// Cursor gets reset into second line from bottom, left most column
@@ -1302,3 +1530,355 @@ void ConptyRoundtripTests::ScrollWithMargins()
// Verify the terminal side.
verifyBufferAfter(termTb);
}
void ConptyRoundtripTests::DontWrapMoveCursorInSingleFrame()
{
// See https://github.com/microsoft/terminal/pull/5181#issuecomment-607427840
Log::Comment(L"This is a test for when a line of text exactly wrapped, but "
L"the cursor didn't end the frame at the end of line (waiting "
L"for more wrapped text). We should still move the cursor in "
L"this case.");
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());
auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
_flushFirstFrame();
auto verifyBuffer = [](const TextBuffer& tb) {
// Simple verification: Make sure the cursor is in the correct place,
// and that it's visible. We don't care so much about the buffer
// contents in this test.
const COORD expectedCursor{ 8, 3 };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
VERIFY_IS_TRUE(tb.GetCursor().IsVisible());
};
hostSm.ProcessString(L"\x1b[?25l");
hostSm.ProcessString(L"\x1b[H");
hostSm.ProcessString(L"\x1b[75C");
hostSm.ProcessString(L"XXXXX");
hostSm.ProcessString(L"\x1b[4;9H");
hostSm.ProcessString(L"\x1b[?25h");
Log::Comment(L"Checking the host buffer state");
verifyBuffer(hostTb);
expectedOutput.push_back("\x1b[75C");
expectedOutput.push_back("XXXXX");
expectedOutput.push_back("\x1b[4;9H");
// We're _not_ expecting a cursor on here, because we didn't actually hide
// the cursor during the course of this frame
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"Checking the terminal buffer state");
verifyBuffer(termTb);
}
void ConptyRoundtripTests::ClearHostTrickeryTest()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"Data:paintEachNewline", L"{0, 1, 2}")
TEST_METHOD_PROPERTY(L"Data:cursorOnNextLine", L"{false, true}")
TEST_METHOD_PROPERTY(L"Data:paintAfterDECALN", L"{false, true}")
TEST_METHOD_PROPERTY(L"Data:changeAttributes", L"{false, true}")
TEST_METHOD_PROPERTY(L"Data:useLongSpaces", L"{false, true}")
TEST_METHOD_PROPERTY(L"Data:printTextAfterSpaces", L"{false, true}")
END_TEST_METHOD_PROPERTIES();
constexpr int PaintEveryNewline = 0;
constexpr int PaintAfterAllNewlines = 1;
constexpr int DontPaintAfterNewlines = 2;
INIT_TEST_PROPERTY(int, paintEachNewline, L"Any of: manually PaintFrame after each newline is emitted, once at the end of all newlines, or not at all");
INIT_TEST_PROPERTY(bool, cursorOnNextLine, L"Either leave the cursor on the first line, or place it on the second line of the buffer");
INIT_TEST_PROPERTY(bool, paintAfterDECALN, L"Controls whether we manually paint a frame after the DECALN sequence is emitted.");
INIT_TEST_PROPERTY(bool, changeAttributes, L"If true, change the text attributes after the 'A's and spaces");
INIT_TEST_PROPERTY(bool, useLongSpaces, L"If true, print 10 spaces instead of 5, longer than a CUF sequence.");
INIT_TEST_PROPERTY(bool, printTextAfterSpaces, L"If true, print \"ZZZZZ\" after the spaces on the first line.");
// See https://github.com/microsoft/terminal/issues/5039#issuecomment-606833841
Log::Comment(L"This is a more than comprehensive test for GH#5039. We're "
L"going to print some text to the buffer, then fill the alt-"
L"buffer with text, then switch back to the main buffer. The "
L"text from the alt buffer should not pollute the main buffer.");
// The text we're printing will look like one of the following, with the
// cursor on the _
// * cursorOnNextLine=false, useLongSpaces=false:
// AAAAA ZZZZZ_
// * cursorOnNextLine=false, useLongSpaces=true:
// AAAAA ZZZZZ_
// * cursorOnNextLine=true, useLongSpaces=false:
// AAAAA ZZZZZ
// BBBBB_
// * cursorOnNextLine=true, useLongSpaces=true:
// AAAAA ZZZZZ
// BBBBB_
//
// If printTextAfterSpaces=false, then we won't print the "ZZZZZ"
//
// The interesting case that repros the bug in GH#5039 is
// - paintEachNewline=DontPaintAfterNewlines (2)
// - cursorOnNextLine=false
// - paintAfterDECALN=<any>
// - changeAttributes=true
// - useLongSpaces=<any>
// - printTextAfterSpaces=<any>
//
// All the possible cases are left here though, to catch potential future regressions.
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());
auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
_flushFirstFrame();
auto verifyBuffer = [&cursorOnNextLine, &useLongSpaces, &printTextAfterSpaces](const TextBuffer& tb,
const til::rectangle viewport) {
// We _would_ expect the Terminal's cursor to be on { 8, 0 }, but this
// is currently broken due to #381/#4676. So we'll use the viewport
// provided to find the actual Y position of the cursor.
const short viewTop = viewport.origin().y<short>();
const short cursorRow = viewTop + (cursorOnNextLine ? 1 : 0);
const short cursorCol = (cursorOnNextLine ? 5 :
(10 + (useLongSpaces ? 5 : 0) + (printTextAfterSpaces ? 5 : 0)));
const COORD expectedCursor{ cursorCol, cursorRow };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
VERIFY_IS_TRUE(tb.GetCursor().IsVisible());
auto iter = TestUtils::VerifyExpectedString(tb, L"AAAAA", { 0, viewTop });
TestUtils::VerifyExpectedString(useLongSpaces ? L" " : L" ", iter);
if (printTextAfterSpaces)
{
TestUtils::VerifyExpectedString(L"ZZZZZ", iter);
}
else
{
TestUtils::VerifyExpectedString(L" ", iter);
}
TestUtils::VerifyExpectedString(L" ", iter);
if (cursorOnNextLine)
{
TestUtils::VerifyExpectedString(tb, L"BBBBB", { 0, cursorRow });
}
};
// We're _not_ checking the conpty output during this test, only the side effects.
_checkConptyOutput = false;
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
Log::Comment(L"Setting up the host buffer...");
hostSm.ProcessString(L"AAAAA");
hostSm.ProcessString(useLongSpaces ? L" " : L" ");
if (changeAttributes)
{
hostSm.ProcessString(L"\x1b[44m");
}
if (printTextAfterSpaces)
{
hostSm.ProcessString(L"ZZZZZ");
}
hostSm.ProcessString(L"\x1b[0m");
if (cursorOnNextLine)
{
hostSm.ProcessString(L"\n");
hostSm.ProcessString(L"BBBBB");
}
Log::Comment(L"Painting after the initial setup.");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"Switching to the alt buffer and using DECALN to fill it with 'E's");
hostSm.ProcessString(L"\x1b[?1049h");
hostSm.ProcessString(L"\x1b#8");
if (paintAfterDECALN)
{
VERIFY_SUCCEEDED(renderer.PaintFrame());
}
for (auto i = 0; i < si.GetViewport().Height(); i++)
{
hostSm.ProcessString(L"\n");
if (paintEachNewline == PaintEveryNewline)
{
VERIFY_SUCCEEDED(renderer.PaintFrame());
}
}
if (paintEachNewline == PaintAfterAllNewlines)
{
VERIFY_SUCCEEDED(renderer.PaintFrame());
}
Log::Comment(L"Returning to the main buffer.");
hostSm.ProcessString(L"\x1b[?1049l");
Log::Comment(L"Checking the host buffer state");
verifyBuffer(hostTb, si.GetViewport().ToInclusive());
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"Checking the terminal buffer state");
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
}
void ConptyRoundtripTests::OverstrikeAtBottomOfBuffer()
{
// See https://github.com/microsoft/terminal/pull/5181#issuecomment-607545241
Log::Comment(L"This test replicates the zsh menu-complete functionality. In"
L" the course of a single frame, we're going to both scroll "
L"the frame and print multiple lines of text above the bottom line.");
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());
auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
_flushFirstFrame();
auto verifyBuffer = [](const TextBuffer& tb,
const til::rectangle viewport) {
const auto lastRow = viewport.bottom<short>() - 1;
const til::point expectedCursor{ 0, lastRow - 1 };
VERIFY_ARE_EQUAL(expectedCursor, til::point{ tb.GetCursor().GetPosition() });
VERIFY_IS_TRUE(tb.GetCursor().IsVisible());
TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA DDDDDDDDDD", til::point{ 0, lastRow - 2 });
TestUtils::VerifyExpectedString(tb, L"BBBBBBBBBB", til::point{ 0, lastRow - 1 });
TestUtils::VerifyExpectedString(tb, L"FFFFFFFFFE", til::point{ 0, lastRow });
};
_logConpty = true;
// We're _not_ checking the conpty output during this test, only the side effects.
_checkConptyOutput = false;
hostSm.ProcessString(L"\x1b#8");
hostSm.ProcessString(L"\x1b[32;1H");
hostSm.ProcessString(L"\x1b[J");
hostSm.ProcessString(L"AAAAAAAAAA");
hostSm.ProcessString(L"\x1b[K");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"\n");
hostSm.ProcessString(L"BBBBBBBBBB");
hostSm.ProcessString(L"\x1b[K");
hostSm.ProcessString(L"\n");
hostSm.ProcessString(L"CCCCCCCCCC");
hostSm.ProcessString(L"\x1b[2A");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"\x1b[20C");
hostSm.ProcessString(L"DDDDDDDDDD");
hostSm.ProcessString(L"\x1b[K");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"\n");
hostSm.ProcessString(L"\x1b[1B");
hostSm.ProcessString(L"EEEEEEEEEE");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"FFFFFFFFF");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"\x1b[A");
hostSm.ProcessString(L"\x1b[A");
hostSm.ProcessString(L"\n");
Log::Comment(L"========== Checking the host buffer state ==========");
verifyBuffer(hostTb, si.GetViewport().ToInclusive());
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state ==========");
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
}
void ConptyRoundtripTests::MarginsWithStatusLine()
{
// See https://github.com/microsoft/terminal/issues/5161
Log::Comment(L"TODO: description");
VERIFY_IS_NOT_NULL(_pVtRenderEngine.get());
auto& g = ServiceLocator::LocateGlobals();
auto& renderer = *g.pRender;
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
_flushFirstFrame();
auto verifyBuffer = [](const TextBuffer& tb,
const til::rectangle viewport) {
const auto lastRow = viewport.bottom<short>() - 1;
const til::point expectedCursor{ 0, lastRow - 1 };
VERIFY_ARE_EQUAL(expectedCursor, til::point{ tb.GetCursor().GetPosition() });
VERIFY_IS_TRUE(tb.GetCursor().IsVisible());
TestUtils::VerifyExpectedString(tb, L"AAAAAAAAAA DDDDDDDDDD", til::point{ 0, lastRow - 2 });
TestUtils::VerifyExpectedString(tb, L"BBBBBBBBBB", til::point{ 0, lastRow - 1 });
TestUtils::VerifyExpectedString(tb, L"FFFFFFFFFE", til::point{ 0, lastRow });
};
_logConpty = true;
// We're _not_ checking the conpty output during this test, only the side effects.
_checkConptyOutput = false;
hostSm.ProcessString(L"\x1b#8");
hostSm.ProcessString(L"\x1b[1;30r");
hostSm.ProcessString(L"\x1b[30;1H");
hostSm.ProcessString(L"\x1b[J");
hostSm.ProcessString(L"AAAAAAAAAA");
hostSm.ProcessString(L"\x1b[K");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"\n");
hostSm.ProcessString(L"BBBBBBBBBB");
hostSm.ProcessString(L"\x1b[K");
hostSm.ProcessString(L"\n");
hostSm.ProcessString(L"CCCCCCCCCC");
hostSm.ProcessString(L"\x1b[2A");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"\x1b[20C");
hostSm.ProcessString(L"DDDDDDDDDD");
hostSm.ProcessString(L"\x1b[K");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"\n");
hostSm.ProcessString(L"\x1b[1B");
hostSm.ProcessString(L"EEEEEEEEEE");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"FFFFFFFFF");
hostSm.ProcessString(L"\r");
hostSm.ProcessString(L"\x1b[A");
hostSm.ProcessString(L"\x1b[A");
hostSm.ProcessString(L"\n");
Log::Comment(L"========== Checking the host buffer state ==========");
verifyBuffer(hostTb, si.GetViewport().ToInclusive());
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state ==========");
verifyBuffer(termTb, term->_mutableViewport.ToInclusive());
}

View File

@@ -27,6 +27,9 @@ using namespace Microsoft::Console::Types;
class ConptyOutputTests
{
static const SHORT TerminalViewWidth = 80;
static const SHORT TerminalViewHeight = 32;
// This test class is to write some things into the PTY and then check that
// the rendering that is coming out of the VT-sequence generator is exactly
// as we expect it to be.
@@ -40,7 +43,7 @@ class ConptyOutputTests
m_state->InitEvents();
m_state->PrepareGlobalFont();
m_state->PrepareGlobalScreenBuffer();
m_state->PrepareGlobalScreenBuffer(TerminalViewWidth, TerminalViewHeight, TerminalViewWidth, TerminalViewHeight);
m_state->PrepareGlobalInputBuffer();
return true;
@@ -66,7 +69,7 @@ class ConptyOutputTests
gci.SetDefaultBackgroundColor(INVALID_COLOR);
gci.SetFillAttribute(0x07); // DARK_WHITE on DARK_BLACK
m_state->PrepareNewTextBufferInfo(true);
m_state->PrepareNewTextBufferInfo(true, TerminalViewWidth, TerminalViewHeight);
auto& currentBuffer = gci.GetActiveOutputBuffer();
// Make sure a test hasn't left us in the alt buffer on accident
VERIFY_IS_FALSE(currentBuffer._IsAltBuffer());
@@ -347,7 +350,6 @@ void ConptyOutputTests::InvalidateUntilOneBeforeEnd()
expectedOutput.push_back("\x1b[65C");
expectedOutput.push_back("ABCDEFGHIJKLMNO");
expectedOutput.push_back("\x1b[1;80H"); // we move the cursor to the end of the line after paint
VERIFY_SUCCEEDED(renderer.PaintFrame());
@@ -367,7 +369,5 @@ void ConptyOutputTests::InvalidateUntilOneBeforeEnd()
expectedOutput.push_back("\x1b[13X");
expectedOutput.push_back("\x1b[13C");
expectedOutput.push_back("\x1b[?25h"); // we turn the cursor back on for good measure
VERIFY_SUCCEEDED(renderer.PaintFrame());
}

View File

@@ -105,7 +105,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
// by prepending a cursor off.
if (_lastCursorIsVisible)
{
_buffer.insert(0, "\x1b[25l");
_buffer.insert(0, "\x1b[?25l");
_lastCursorIsVisible = false;
}
// If the cursor was NOT previously visible, then that's fine! we don't
@@ -214,7 +214,35 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
// _nextCursorIsVisible will still be false (from when we set it during
// StartPaint)
_nextCursorIsVisible = true;
return VtEngine::PaintCursor(options);
// If we did a delayed EOL wrap because we actually wrapped the line here,
// then don't PaintCursor. When we're at the EOL because we've wrapped, our
// internal _lastText thinks the cursor is on the cell just past the right
// of the viewport (ex { 120, 0 }). However, conhost thinks the cursor is
// actually on the last cell of the row. So it'll tell us to paint the
// cursor at { 119, 0 }. If we do that movement, then we'll break line
// wrapping.
// See GH#5113, GH#1245, GH#357
const auto nextCursorPosition = options.coordCursor;
// Only skip this paint when we think the cursor is in the cell
// immediately off the edge of the terminal, and the actual cursor is in
// the last cell of the row. We're in a deferred wrap, but the host
// thinks the cursor is actually in-frame.
// See ConptyRoundtripTests::DontWrapMoveCursorInSingleFrame
const bool cursorIsInDeferredWrap = (nextCursorPosition.X == _lastText.X - 1) && (nextCursorPosition.Y == _lastText.Y);
// If all three of these conditions are true, then:
// * cursorIsInDeferredWrap: The cursor is in a position where the line
// filled the last cell of the row, but the host tried to paint it in
// the last cell anyways
// * _delayedEolWrap && _wrappedRow.has_value(): We think we've deferred
// the wrap of a line.
// If they're all true, DON'T manually paint the cursor this frame.
if (!(cursorIsInDeferredWrap && _delayedEolWrap && _wrappedRow.has_value()))
{
return VtEngine::PaintCursor(options);
}
return S_OK;
}
// Routine Description:
@@ -232,9 +260,9 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
[[nodiscard]] HRESULT XtermEngine::_MoveCursor(COORD const coord) noexcept
{
HRESULT hr = S_OK;
const auto originalPos = _lastText;
_trace.TraceMoveCursor(_lastText, coord);
bool performedSoftWrap = false;
if (coord.X != _lastText.X || coord.Y != _lastText.Y)
{
if (coord.X == 0 && coord.Y == 0)
@@ -260,6 +288,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
if (previousLineWrapped)
{
performedSoftWrap = true;
_trace.TraceWrapped();
hr = S_OK;
}
@@ -318,10 +347,7 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
_lastText = coord;
}
}
if (_lastText.Y != _lastViewport.ToOrigin().BottomInclusive())
{
_newBottomLine = false;
}
_deferredCursorPos = INVALID_COORDS;
_wrappedRow = std::nullopt;
@@ -345,6 +371,8 @@ XtermEngine::XtermEngine(_In_ wil::unique_hfile hPipe,
[[nodiscard]] HRESULT XtermEngine::ScrollFrame() noexcept
try
{
_trace.TraceScrollFrame(_scrollDelta);
if (_scrollDelta.x() != 0)
{
// No easy way to shift left-right. Everything needs repainting.
@@ -356,41 +384,85 @@ try
return S_OK;
}
const short dy = _scrollDelta.y<SHORT>();
const short dy = _scrollDelta.y<short>();
const short absDy = static_cast<short>(abs(dy));
HRESULT hr = S_OK;
if (dy < 0)
{
// Instead of deleting the first line (causing everything to move up)
// move to the bottom of the buffer, and newline.
// That will cause everything to move up, by moving the viewport down.
// This will let remote conhosts scroll up to see history like normal.
const short bottom = _lastViewport.ToOrigin().BottomInclusive();
hr = _MoveCursor({ 0, bottom });
if (SUCCEEDED(hr))
{
std::string seq = std::string(absDy, '\n');
hr = _Write(seq);
// Mark that the bottom line is new, so we won't spend time with an
// ECH on it.
_newBottomLine = true;
}
// We don't need to _MoveCursor the cursor again, because it's still
// at the bottom of the viewport.
}
else if (dy > 0)
{
// Move to the top of the buffer, and insert some lines of text, to
// cause the viewport contents to shift down.
hr = _MoveCursor({ 0, 0 });
if (SUCCEEDED(hr))
{
hr = _InsertLine(absDy);
}
// Save the old wrap state here. We're going to clear it so that
// _MoveCursor will definitely move us to the right position. We'll
// restore the state afterwards.
const auto oldWrappedRow = _wrappedRow;
const auto oldDelayedEolWrap = _delayedEolWrap;
_delayedEolWrap = false;
_wrappedRow = std::nullopt;
// TODO GH#5228 - We could optimize this by only doing this newline work
// when there's more invalid than just the bottom line. If only the
// bottom line is invalid, then the next thing the Renderer is going to
// tell us to do is print the new line at the bottom of the viewport,
// and _MoveCursor will automatically give us the newline we want.
// When that's implemented, we'll probably want to make sure to add a
// _lastText.Y += dy;
// statement here.
// Move the cursor to the bottom of the current viewport
const short bottom = _lastViewport.BottomInclusive();
RETURN_IF_FAILED(_MoveCursor({ 0, bottom }));
// Emit some number of newlines to create space in the buffer.
RETURN_IF_FAILED(_Write(std::string(absDy, '\n')));
// Restore our wrap state.
_wrappedRow = oldWrappedRow;
_delayedEolWrap = oldDelayedEolWrap;
}
return hr;
// Shift our internal tracker of the last text position according to how
// much we've scrolled. If we manually scroll the buffer right now, by
// moving the cursor to the bottom row of the viewport and emitting a
// newline, we'll cause any wrapped lines to get broken.
//
// Instead, we'll just update our internal tracker of where the buffer
// contents are. On this frame, we'll then still move the cursor correctly
// relative to the new frame contents. To do this, we'll shift our
// coordinates we're tracking, like the row that we wrapped on and the
// position we think we left the cursor.
//
// See GH#5113
_trace.TraceLastText(_lastText);
if (_wrappedRow.has_value())
{
_wrappedRow.value() += dy;
_trace.TraceSetWrapped(_wrappedRow.value());
}
if (_delayedEolWrap && _wrappedRow.has_value())
{
// If we wrapped the last line, and we're in the middle of painting it,
// then the newline we did above just manually broke the line. What
// we're doing here is a hack: we're going to manually re-invalidate the
// last character of the wrapped row. When the PaintBufferLine calls
// come back through, we'll paint this last character again, causing us
// to get into the wrapped state once again. This is the only way to
// ensure that if a line was wrapped, and we painted the first line in
// one frame, and the second line in another frame that included other
// changes _above_ the wrapped line, that we maintain the wrap state in
// the Terminal.
const til::rectangle lastCellOfWrappedRow{
til::point{ _lastViewport.RightInclusive(), _wrappedRow.value() },
til::size{ 1, 1 }
};
_trace.TraceInvalidate(lastCellOfWrappedRow);
_invalidMap.set(lastCellOfWrappedRow);
}
// If the entire viewport was invalidated this frame, don't mark the bottom
// line as new. There are cases where this can cause visual artifacts - see
// GH#5039 and ConptyRoundtripTests::ClearHostTrickeryTest
const bool allInvalidated = _invalidMap.all();
_newBottomLine = !allInvalidated;
return S_OK;
}
CATCH_RETURN();

View File

@@ -32,7 +32,12 @@ using namespace Microsoft::Console::Types;
_titleChanged;
_quickReturn = !somethingToDo;
_trace.TraceStartPaint(_quickReturn, _invalidMap, _lastViewport.ToInclusive(), _scrollDelta, _cursorMoved);
_trace.TraceStartPaint(_quickReturn,
_invalidMap,
_lastViewport.ToInclusive(),
_scrollDelta,
_cursorMoved,
_wrappedRow);
return _quickReturn ? S_FALSE : S_OK;
}
@@ -442,6 +447,8 @@ using namespace Microsoft::Console::Types;
// If we're not using erase char, but we did erase all at the start of the
// frame, don't add spaces at the end.
const bool removeSpaces = (useEraseChar || (_clearedAllThisFrame) || (_newBottomLine));
// This fixes the bug, but why?
// const bool removeSpaces = (useEraseChar || (_clearedAllThisFrame) || (_newBottomLine && coord.Y == _lastViewport.BottomInclusive()));
const size_t cchActual = removeSpaces ?
(cchLine - numSpaces) :
cchLine;
@@ -458,6 +465,7 @@ using namespace Microsoft::Console::Types;
// the cursor is still waiting on that character for the next character
// to follow it.
_wrappedRow = std::nullopt;
_trace.TraceClearWrapped();
}
// Move the cursor to the start of this run.
@@ -479,6 +487,7 @@ using namespace Microsoft::Console::Types;
lastWrittenChar > _lastViewport.RightInclusive())
{
_wrappedRow = coord.Y;
_trace.TraceSetWrapped(coord.Y);
}
// Update our internal tracker of the cursor's position.
@@ -546,7 +555,7 @@ using namespace Microsoft::Console::Types;
{
_deferredCursorPos = { _lastText.X + sNumSpaces, _lastText.Y };
}
else
else if (numSpaces > 0)
{
std::wstring spaces = std::wstring(numSpaces, L' ');
RETURN_IF_FAILED(VtEngine::_WriteTerminalUtf8(spaces));
@@ -555,9 +564,12 @@ using namespace Microsoft::Console::Types;
}
}
// If we previously though that this was a new bottom line, it certainly
// isn't new any longer.
_newBottomLine = false;
// If we printed to the bottom line, and we previously thought that this was
// a new bottom line, it certainly isn't new any longer.
if (coord.Y == _lastViewport.BottomInclusive())
{
_newBottomLine = false;
}
return S_OK;
}

View File

@@ -36,7 +36,6 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
_lastWasBold(false),
_lastViewport(initialViewport),
_invalidMap(initialViewport.Dimensions()),
_lastRealCursor({ 0 }),
_lastText({ 0 }),
_scrollDelta({ 0, 0 }),
_quickReturn(false),

View File

@@ -148,7 +148,8 @@ void RenderTracing::TraceStartPaint(const bool quickReturn,
const til::bitmap invalidMap,
const til::rectangle lastViewport,
const til::point scrollDelt,
const bool cursorMoved) const
const bool cursorMoved,
const std::optional<short>& wrappedRow) const
{
#ifndef UNIT_TESTING
if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
@@ -159,14 +160,29 @@ void RenderTracing::TraceStartPaint(const bool quickReturn,
const auto lastView = lastViewStr.c_str();
const auto scrollDeltaStr = scrollDelt.to_string();
const auto scrollDelta = scrollDeltaStr.c_str();
TraceLoggingWrite(g_hConsoleVtRendererTraceProvider,
"VtEngine_TraceStartPaint",
TraceLoggingBool(quickReturn),
TraceLoggingWideString(invalidated),
TraceLoggingWideString(lastView),
TraceLoggingWideString(scrollDelta),
TraceLoggingBool(cursorMoved),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
if (wrappedRow.has_value())
{
TraceLoggingWrite(g_hConsoleVtRendererTraceProvider,
"VtEngine_TraceStartPaint",
TraceLoggingBool(quickReturn),
TraceLoggingWideString(invalidated),
TraceLoggingWideString(lastView),
TraceLoggingWideString(scrollDelta),
TraceLoggingBool(cursorMoved),
TraceLoggingValue(wrappedRow.value()),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
}
else
{
TraceLoggingWrite(g_hConsoleVtRendererTraceProvider,
"VtEngine_TraceStartPaint",
TraceLoggingBool(quickReturn),
TraceLoggingWideString(invalidated),
TraceLoggingWideString(lastView),
TraceLoggingWideString(scrollDelta),
TraceLoggingBool(cursorMoved),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
}
}
#else
UNREFERENCED_PARAMETER(quickReturn);
@@ -174,6 +190,7 @@ void RenderTracing::TraceStartPaint(const bool quickReturn,
UNREFERENCED_PARAMETER(lastViewport);
UNREFERENCED_PARAMETER(scrollDelt);
UNREFERENCED_PARAMETER(cursorMoved);
UNREFERENCED_PARAMETER(wrappedRow);
#endif UNIT_TESTING
}
@@ -203,6 +220,24 @@ void RenderTracing::TraceLastText(const til::point lastTextPos) const
UNREFERENCED_PARAMETER(lastTextPos);
#endif UNIT_TESTING
}
void RenderTracing::TraceScrollFrame(const til::point scrollDeltaPos) const
{
#ifndef UNIT_TESTING
if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
{
const auto scrollDeltaStr = scrollDeltaPos.to_string();
const auto scrollDelta = scrollDeltaStr.c_str();
TraceLoggingWrite(g_hConsoleVtRendererTraceProvider,
"VtEngine_TraceScrollFrame",
TraceLoggingWideString(scrollDelta),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
}
#else
UNREFERENCED_PARAMETER(scrollDeltaPos);
#endif UNIT_TESTING
}
void RenderTracing::TraceMoveCursor(const til::point lastTextPos, const til::point cursor) const
{
#ifndef UNIT_TESTING
@@ -241,6 +276,36 @@ void RenderTracing::TraceWrapped() const
#endif UNIT_TESTING
}
void RenderTracing::TraceSetWrapped(const short wrappedRow) const
{
#ifndef UNIT_TESTING
if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
{
TraceLoggingWrite(g_hConsoleVtRendererTraceProvider,
"VtEngine_TraceSetWrapped",
TraceLoggingValue(wrappedRow),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
}
#else
UNREFERENCED_PARAMETER(wrappedRow);
#endif UNIT_TESTING
}
void RenderTracing::TraceClearWrapped() const
{
#ifndef UNIT_TESTING
if (TraceLoggingProviderEnabled(g_hConsoleVtRendererTraceProvider, WINEVENT_LEVEL_VERBOSE, 0))
{
const auto* const msg = "Cleared wrap state";
TraceLoggingWrite(g_hConsoleVtRendererTraceProvider,
"VtEngine_TraceClearWrapped",
TraceLoggingString(msg),
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
}
#else
#endif UNIT_TESTING
}
void RenderTracing::TracePaintCursor(const til::point coordCursor) const
{
#ifndef UNIT_TESTING

View File

@@ -29,7 +29,10 @@ namespace Microsoft::Console::VirtualTerminal
void TraceString(const std::string_view& str) const;
void TraceInvalidate(const til::rectangle view) const;
void TraceLastText(const til::point lastText) const;
void TraceScrollFrame(const til::point scrollDelta) const;
void TraceMoveCursor(const til::point lastText, const til::point cursor) const;
void TraceSetWrapped(const short wrappedRow) const;
void TraceClearWrapped() const;
void TraceWrapped() const;
void TracePaintCursor(const til::point coordCursor) const;
void TraceInvalidateAll(const til::rectangle view) const;
@@ -39,7 +42,8 @@ namespace Microsoft::Console::VirtualTerminal
const til::bitmap invalidMap,
const til::rectangle lastViewport,
const til::point scrollDelta,
const bool cursorMoved) const;
const bool cursorMoved,
const std::optional<short>& wrappedRow) const;
void TraceEndPaint() const;
};
}

View File

@@ -124,7 +124,6 @@ namespace Microsoft::Console::Render
til::bitmap _invalidMap;
COORD _lastRealCursor;
COORD _lastText;
til::point _scrollDelta;