Compare commits

...

39 Commits

Author SHA1 Message Date
Dustin L. Howett
520a550655 Migrate spelling-0.0.21 changes from main 2022-04-01 06:55:32 -05:00
Mike Griese
84d68f082e bugfixes for the demo 2022-04-01 06:55:32 -05:00
Mike Griese
41796c2409 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/menu-complete-prototype 2022-04-01 05:49:12 -05:00
Mike Griese
9eb77cf0f1 acrylic because this is a TRANSIENT surface 2022-03-23 12:55:34 -05:00
Mike Griese
9cbb172323 resize down when there are few entries 2022-03-23 11:56:27 -05:00
Mike Griese
6e2f53b025 populates menu before opening 2022-03-23 11:45:04 -05:00
Mike Griese
d1afa2af14 relative positioning of the menu 2022-03-22 16:59:27 -05:00
Mike Griese
e52549ace0 Man okay so popups just work instantly, that's awesome 2022-03-22 16:24:43 -05:00
Mike Griese
60f63b09cc Preview the input via the TSF input control. This is awesome, and should go into main 2022-03-22 06:00:06 -05:00
Mike Griese
64c2e856cc This is an e2e prototype for #3121. No shell integration, but works more or less. 2022-03-21 15:21:19 -05:00
Mike Griese
bfebcf248d thru to the command palette 2022-03-21 12:26:00 -05:00
Mike Griese
4d1570f4b4 bubble up thru TermControl 2022-03-21 11:00:22 -05:00
Mike Griese
3a48e19b1d this is a noticably dumber implementation but whatever 2022-03-21 10:25:04 -05:00
Mike Griese
cb81e61949 I thought this was so clever and then I remembered that you can't use any control chars in OSC strings. Fuck that 2022-03-21 10:14:18 -05:00
Mike Griese
e3181e76c9 Merge remote-tracking branch 'origin/main' into dev/migrie/fhl/menu-complete-prototype 2022-03-21 08:26:29 -05:00
Mike Griese
0163878d23 cleanup 2022-03-18 08:26:49 -05:00
Mike Griese
c8f0a5e5d5 Merge branch 'dev/migrie/b/alt-buffer-terminal' into dev/migrie/b/3493-no-wrap-alt-buffer 2022-03-17 15:59:26 -05:00
Mike Griese
65b457113d notes from j4james 2022-03-17 14:32:03 -05:00
Mike Griese
7237fced16 thats not a word either 2022-03-17 14:23:20 -05:00
Mike Griese
bf3d79e41a fine that's not a word 2022-03-16 10:37:05 -05:00
Mike Griese
0cfb4637e2 Merge remote-tracking branch 'origin/main' into dev/migrie/b/alt-buffer-terminal 2022-03-16 10:25:02 -05:00
Mike Griese
4c96fc08a1 Merge branch 'dev/migrie/b/alt-buffer-terminal' into dev/migrie/b/3493-no-wrap-alt-buffer 2022-03-08 17:01:22 -06:00
Mike Griese
e658431c11 Merge remote-tracking branch 'origin/main' into dev/migrie/b/alt-buffer-terminal 2022-03-08 16:57:07 -06:00
Mike Griese
9453aa5ee1 More test cleanup. Make sure viewport doesnt move 2022-03-08 16:54:29 -06:00
Mike Griese
0a1ed70153 I thought this was a test for https://github.com/microsoft/terminal/pull/12561#discussion_r814337255, but I think that "just worked" because conpty magic. 2022-03-08 16:49:22 -06:00
Mike Griese
69d0973f14 make this test way more elaborate 2022-03-08 16:20:29 -06:00
Mike Griese
57094b7d98 start writing tests 2022-03-08 15:56:49 -06:00
Mike Griese
54dc30411c Stashing this for now. I think this does the save/restore cursor stuff that we're supposed to do when entering/exiting the alt buffer 2022-02-28 12:19:50 -06:00
Mike Griese
5d8c0d0b9b comments mostly 2022-02-25 06:01:30 -06:00
Mike Griese
65295796f2 deferred resizing both in the Terminal and the ConPTY 2022-02-25 05:48:34 -06:00
Mike Griese
d08d21626f defer main buffer resizes till we exit, to try and prevent flashing in conpty. That didn't work, unfortunately 2022-02-25 04:22:37 -06:00
Mike Griese
57280d8961 I think this does the whole thing 2022-02-24 16:00:45 -06:00
Mike Griese
60d2c2e26d fix tests 2022-02-24 12:33:20 -06:00
Mike Griese
dff1b94016 spel 2022-02-24 11:45:52 -06:00
Mike Griese
bf24cdd4b0 more comments are always good 2022-02-23 16:14:36 -06:00
Mike Griese
1209fa40c3 one last comment 2022-02-23 16:10:07 -06:00
Mike Griese
dd702c769d Most of the remaining todos, comments 2022-02-23 16:01:09 -06:00
Mike Griese
e94e08c303 This quite nearly implements everything for the Terminal half
Resizing is surely boned but this is 1000% percent better than nothing at all.
2022-02-23 15:29:59 -06:00
Mike Griese
83466a4381 I think this is the conhost half of the changes 2022-02-23 11:20:36 -06:00
83 changed files with 2569 additions and 1154 deletions

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.

View File

@@ -1,4 +1,4 @@
<!-- markdownlint-disable MD033 MD041 -->
<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details>
<summary>
:pencil2: Contributor please read this
@@ -6,7 +6,7 @@
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...
: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:
@@ -20,31 +20,29 @@ 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>:clamp: If you see a bunch of garbage</summary>
If it relates to a ...
<details><summary>well-formed pattern</summary>
<details><summary>If the flagged items are :exploding_head: false positives</summary>
See if there's a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it.
If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).
If not, try writing one and adding it to a `patterns/{file}.txt`.
Please add a file path to the `excludes.txt` file matching the containing 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><summary>binary-ish string</summary>
Please add a file path to the `excludes.txt` file instead of just accepting the garbage.
File paths are Perl 5 Regular Expressions - you can [test](
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](
`^` 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).
</details>
* 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,20 +1,21 @@
admins
apc
allcolors
Apc
bsd
apc
breadcrumb
breadcrumbs
bsd
calt
CMMI
ccmp
changelog
clickable
clig
CMMI
copyable
cybersecurity
dalet
dcs
Dcs
dcs
dialytika
dje
downside
@@ -26,36 +27,43 @@ 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
noreply
nje
noreply
ogonek
@@ -76,13 +84,16 @@ runtimes
shcha
slnt
Sos
ssh
timeline
timelines
timestamped
TLDR
tokenizes
tonos
toolset
tshe
ubuntu
uiatextrange
UIs
und
@@ -91,6 +102,7 @@ versioned
vsdevcmd
We'd
wildcards
XBox
YBox
yeru
zhe
allcolors

View File

@@ -5,6 +5,7 @@ aclapi
alignas
alignof
APPLYTOSUBMENUS
appxrecipe
bitfield
bitfields
BUILDBRANCH
@@ -14,6 +15,7 @@ BYCOMMAND
BYPOSITION
charconv
CLASSNOTAVAILABLE
CLOSEAPP
cmdletbinding
COLORPROPERTY
colspan
@@ -28,9 +30,14 @@ dataobject
dcomp
DERR
dlldata
DNE
DONTADDTORECENT
DWMSBT
DWMWA
DWMWA
DWORDLONG
endfor
ENDSESSION
enumset
environstrings
EXPCMDFLAGS
@@ -70,6 +77,7 @@ IDirect
IExplorer
IFACEMETHOD
IFile
IGraphics
IInheritable
IMap
IMonarch
@@ -84,6 +92,7 @@ istream
IStringable
ITab
ITaskbar
itow
IUri
IVirtual
KEYSELECT
@@ -95,12 +104,15 @@ lround
Lsa
lsass
LSHIFT
LTGRAY
MAINWINDOW
memchr
memicmp
MENUCOMMAND
MENUDATA
MENUITEMINFOW
MENUINFO
MENUITEMINFOW
mmeapi
MOUSELEAVE
mov
mptt
@@ -136,14 +148,17 @@ OUTLINETEXTMETRICW
overridable
PACL
PAGESCROLL
PATINVERT
PEXPLICIT
PICKFOLDERS
pmr
ptstr
QUERYENDSESSION
rcx
REGCLS
RETURNCMD
rfind
ROOTOWNER
roundf
RSHIFT
SACL
@@ -153,6 +168,7 @@ serializer
SETVERSION
SHELLEXECUTEINFOW
shobjidl
SHOWHIDE
SHOWMINIMIZED
SHOWTIP
SINGLEUSE
@@ -173,6 +189,8 @@ Stubless
Subheader
Subpage
syscall
SYSTEMBACKDROP
TABROW
TASKBARCREATED
TBPF
THEMECHANGED
@@ -192,6 +210,8 @@ UOI
UPDATEINIFILE
userenv
USEROBJECTFLAGS
Viewbox
virtualalloc
wcsstr
wcstoui
winmain

View File

@@ -1,8 +1,10 @@
Anup
austdi
arkthur
Ballmer
bhoj
Bhojwani
Bluloco
carlos
dhowett
Diviness
@@ -22,6 +24,7 @@ Hernan
Howett
Illhardt
iquilezles
italo
jantari
jerrysh
Kaiyu
@@ -35,7 +38,9 @@ leonmsft
Lepilleur
lhecker
lukesampson
Macbook
Manandhar
masserano
mbadolato
Mehrain
menger
@@ -64,10 +69,13 @@ Rincewind
rprichard
Schoonover
shadertoy
Shomnipotence
simioni
Somuah
sonph
sonpham
stakx
talo
thereses
Walisch
WDX

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-)/

View File

@@ -1,28 +1,39 @@
# 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$
(?:^|/)package(?:-lock|)\.json$
(?:^|/)sources(?:|\.dep)$
SUMS$
(?:^|/)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$
@@ -30,28 +41,53 @@ SUMS$
\.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$
@@ -77,6 +113,5 @@ SUMS$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^src/types/ut_types/UtilsTests.cpp$
^tools/ReleaseEngineering/ServicingPipeline.ps1$
^\.github/actions/spelling/
^\.gitignore$
^\XamlStyler.json$
ignore$
SUMS$

View File

@@ -5,26 +5,19 @@ AAAAAABBBBBBCCC
AAAAABBBBBBCCC
abcd
abcd
abcde
abcdef
ABCDEFG
ABCDEFGH
ABCDEFGHIJ
abcdefghijk
ABCDEFGHIJKLMNO
abcdefghijklmnop
ABCDEFGHIJKLMNOPQRST
abcdefghijklmnopqrstuvwxyz
ABCG
ABE
abf
BBBBB
BBBBBBBB
BBBBBBBBBBBBBBDDDD
BBBBBCCC
BBBBCCCCC
BBGGRR
CCE
EFG
EFGh
QQQQQQQQQQABCDEFGHIJ
@@ -33,7 +26,6 @@ QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
qrstuvwxyz
qwerty
QWERTYUIOP
qwertyuiopasdfg
YYYYYYYDDDDDDDDDDD
ZAAZZ

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +1,6 @@
http
www
easyrgb
php
ecma
rapidtables
WCAG
freedesktop
ycombinator
robertelder
kovidgoyal
leonerd
fixterms
winui
appshellintegration
mdtauk
cppreference
gfycat
Guake
azurewebsites
askubuntu
dostips
viewtopic
rosettacode
Rexx
tldp
HOWTO
uwspace
uwaterloo

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

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

View File

@@ -1,22 +1,12 @@
^attache$
^attacher$
^attachers$
^spae$
^spaebook$
^spaecraft$
^spaed$
^spaedom$
^spaeing$
^spaeings$
^spae-man$
^spaeman$
^spaer$
^Spaerobee$
^spaes$
^spaewife$
^spaewoman$
^spaework$
^spaewright$
^wether$
^wethers$
^wetherteg$
benefitting
occurences?
^dependan.*
^oer$
Sorce
^[Ss]pae.*
^untill$
^untilling$
^wether.*

View File

@@ -1,20 +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:
pull_request_target:
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: checkout-merge
if: "contains(github.event_name, 'pull_request')"
uses: actions/checkout@v2
- name: check-spelling
id: spelling
uses: check-spelling/check-spelling@v0.0.21
with:
ref: refs/pull/${{github.event.pull_request.number}}/merge
- name: checkout
if: "!contains(github.event_name, 'pull_request')"
uses: actions/checkout@v2
- uses: check-spelling/check-spelling@v0.0.19
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 }}

2
gitbranch.cmd Normal file
View File

@@ -0,0 +1,2 @@
@echo off
git branch | D:\dev\private\OpenConsole\bin\x64\Debug\Scratch.exe --prefix "git checkout "

View File

@@ -562,7 +562,7 @@ bool TextBuffer::IncrementCircularBuffer(const bool inVtMode)
// to the logical position 0 in the window (cursor coordinates and all other coordinates).
if (_isActiveBuffer)
{
_renderer.TriggerCircling();
_renderer.TriggerFlush(true);
}
// Prune hyperlinks to delete obsolete references

View File

@@ -50,6 +50,7 @@ namespace winrt::TerminalApp::implementation
{
case ShortcutAction::SetColorScheme:
case ShortcutAction::AdjustOpacity:
case ShortcutAction::SendInput:
{
_RunRestorePreviews();
break;
@@ -140,6 +141,27 @@ namespace winrt::TerminalApp::implementation
});
}
void TerminalPage::_PreviewSendInput(const Settings::Model::SendInputArgs& args)
{
const auto backup = _restorePreviewFuncs.empty();
_ApplyToActiveControls([&](const auto& control) {
// // Stash a copy of the original opacity.
// auto originalOpacity{ control.BackgroundOpacity() };
// Apply the new opacity
control.PreviewInput(args.Input());
if (backup)
{
_restorePreviewFuncs.emplace_back([=]() {
// On dismiss:
control.PreviewInput(L"");
});
}
});
}
// Method Description:
// - Handler for the CommandPalette::PreviewAction event. The Command
// Palette will raise this even when an action is selected, but _not_
@@ -176,6 +198,11 @@ namespace winrt::TerminalApp::implementation
_PreviewAdjustOpacity(args.ActionAndArgs().Args().try_as<AdjustOpacityArgs>());
break;
}
case ShortcutAction::SendInput:
{
_PreviewSendInput(args.ActionAndArgs().Args().try_as<SendInputArgs>());
break;
}
}
// GH#9818 Other ideas for actions that could be preview-able:

View File

@@ -236,13 +236,17 @@ namespace winrt::TerminalApp::implementation
void CommandPalette::_selectedCommandChanged(const IInspectable& /*sender*/,
const Windows::UI::Xaml::RoutedEventArgs& /*args*/)
{
const auto currentlyVisible{ Visibility() == Visibility::Visible };
const auto selectedCommand = _filteredActionsView().SelectedItem();
const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>() };
if (_currentMode == CommandPaletteMode::TabSwitchMode)
{
_switchToTab(filteredCommand);
}
else if (_currentMode == CommandPaletteMode::ActionMode && filteredCommand != nullptr)
else if (_currentMode == CommandPaletteMode::ActionMode &&
filteredCommand != nullptr &&
currentlyVisible)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
{
@@ -1047,7 +1051,9 @@ namespace winrt::TerminalApp::implementation
{
std::copy(begin(commandsToFilter), end(commandsToFilter), std::back_inserter(actions));
}
else if (_currentMode == CommandPaletteMode::TabSearchMode || _currentMode == CommandPaletteMode::ActionMode || _currentMode == CommandPaletteMode::CommandlineMode)
else if (_currentMode == CommandPaletteMode::TabSearchMode ||
_currentMode == CommandPaletteMode::ActionMode ||
_currentMode == CommandPaletteMode::CommandlineMode)
{
for (const auto& action : commandsToFilter)
{
@@ -1314,4 +1320,30 @@ namespace winrt::TerminalApp::implementation
ApplicationState::SharedInstance().RecentCommands(single_threaded_vector(std::move(newRecentCommands)));
}
void CommandPalette::PositionManually(Windows::Foundation::Point origin, Windows::Foundation::Size size)
{
Controls::Grid::SetRow(_backdrop(), 0);
Controls::Grid::SetColumn(_backdrop(), 0);
Controls::Grid::SetRowSpan(_backdrop(), 2);
Controls::Grid::SetColumnSpan(_backdrop(), 3);
// Set thie Max* versions here, otherwise when there are few results,
// the cmdpal will _still_ be 300x300 and filled with empty space
_backdrop().MaxWidth(size.Width);
_backdrop().MaxHeight(size.Height);
_backdrop().HorizontalAlignment(HorizontalAlignment::Stretch);
_backdrop().VerticalAlignment(VerticalAlignment::Stretch);
// We can fake this. We're only using this method for the autocomplete
// version of the cmdpal. Set the BG to acrylic.
const auto colorControlStyle{ Resources().Lookup(winrt::box_value(L"CommandPaletteAcrylicBackground")).as<Windows::UI::Xaml::Style>() };
_backdrop().Style(colorControlStyle);
Windows::UI::Xaml::Thickness margins{};
margins.Left = origin.X;
margins.Top = origin.Y;
_backdrop().Margin(margins);
}
}

View File

@@ -46,6 +46,8 @@ namespace winrt::TerminalApp::implementation
void EnableTabSwitcherMode(const uint32_t startIdx, Microsoft::Terminal::Settings::Model::TabSwitcherMode tabSwitcherMode);
void EnableTabSearchMode();
void PositionManually(Windows::Foundation::Point origin, Windows::Foundation::Size size);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, _PropertyChangedHandlers);

View File

@@ -33,6 +33,8 @@ namespace TerminalApp
void EnableTabSwitcherMode(UInt32 startIdx, Microsoft.Terminal.Settings.Model.TabSwitcherMode tabSwitcherMode);
void EnableTabSearchMode();
void PositionManually(Windows.Foundation.Point origin, Windows.Foundation.Size size);
event Windows.Foundation.TypedEventHandler<CommandPalette, TabBase> SwitchToTabRequested;
event Windows.Foundation.TypedEventHandler<CommandPalette, Microsoft.Terminal.Settings.Model.Command> DispatchCommandRequested;
event Windows.Foundation.TypedEventHandler<CommandPalette, String> CommandLineExecutionRequested;

View File

@@ -228,9 +228,21 @@
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<Style x:Key="CommandPaletteBackground"
<Color x:Key="CommandPaletteBackgroundColor">#333333</Color>
<SolidColorBrush x:Key="CommandPaletteSolidBackgroundBrush"
Color="{ThemeResource CommandPaletteBackgroundColor}" />
<AcrylicBrush x:Key="CommandPaletteAcrylicBackgroundBrush"
BackgroundSource="HostBackdrop"
FallbackColor="{ThemeResource CommandPaletteBackgroundColor}"
TintColor="{ThemeResource CommandPaletteBackgroundColor}"
TintOpacity="0.5" />
<Style x:Key="CommandPaletteSolidBackground"
TargetType="Grid">
<Setter Property="Background" Value="#333333" />
<Setter Property="Background" Value="{ThemeResource CommandPaletteSolidBackgroundBrush}" />
</Style>
<Style x:Key="CommandPaletteAcrylicBackground"
TargetType="Grid">
<Setter Property="Background" Value="{ThemeResource CommandPaletteAcrylicBackgroundBrush}" />
</Style>
<!-- TextBox colors ! -->
<SolidColorBrush x:Key="TextControlBackground"
@@ -291,9 +303,21 @@
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<Style x:Key="CommandPaletteBackground"
<Color x:Key="CommandPaletteBackgroundColor">#CCCCCC</Color>
<SolidColorBrush x:Key="CommandPaletteSolidBackgroundBrush"
Color="{ThemeResource CommandPaletteBackgroundColor}" />
<AcrylicBrush x:Key="CommandPaletteAcrylicBackgroundBrush"
BackgroundSource="HostBackdrop"
FallbackColor="{ThemeResource CommandPaletteBackgroundColor}"
TintColor="{ThemeResource CommandPaletteBackgroundColor}"
TintOpacity="0.5" />
<Style x:Key="CommandPaletteSolidBackground"
TargetType="Grid">
<Setter Property="Background" Value="#CCCCCC" />
<Setter Property="Background" Value="{ThemeResource CommandPaletteSolidBackgroundBrush}" />
</Style>
<Style x:Key="CommandPaletteAcrylicBackground"
TargetType="Grid">
<Setter Property="Background" Value="{ThemeResource CommandPaletteAcrylicBackgroundBrush}" />
</Style>
<!-- TextBox colors ! -->
<SolidColorBrush x:Key="TextControlBackground"
@@ -348,11 +372,14 @@
</Style>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<Style x:Key="CommandPaletteBackground"
<Style x:Key="CommandPaletteSolidBackground"
TargetType="Grid">
<Setter Property="Background" Value="{ThemeResource SystemColorWindowColor}" />
</Style>
<StaticResource x:Key="CommandPaletteAcrylicBackground"
ResourceKey="CommandPaletteSolidBackground" />
<!-- KeyChordText styles (use XAML defaults for High Contrast theme) -->
<Style x:Key="KeyChordBorderStyle"
TargetType="Border" />
@@ -409,7 +436,7 @@
Windows10version1903:Shadow="{StaticResource CommandPaletteShadow}"
CornerRadius="{ThemeResource OverlayCornerRadius}"
PointerPressed="_backdropPointerPressed"
Style="{ThemeResource CommandPaletteBackground}">
Style="{ThemeResource CommandPaletteSolidBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

View File

@@ -254,6 +254,17 @@ namespace winrt::TerminalApp::implementation
CommandPalette().SwitchToTabRequested({ this, &TerminalPage::_OnSwitchToTabRequested });
CommandPalette().PreviewAction({ this, &TerminalPage::_PreviewActionHandler });
AutoCompleteMenu().PositionManually(Windows::Foundation::Point{ 0, 0 }, Windows::Foundation::Size{ 200, 300 });
AutoCompleteMenu().RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) {
if (AutoCompleteMenu().Visibility() == Visibility::Collapsed)
{
AutoCompletePopup().IsOpen(false);
_FocusActiveControl(nullptr, nullptr);
}
});
AutoCompleteMenu().DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested });
AutoCompleteMenu().PreviewAction({ this, &TerminalPage::_PreviewActionHandler });
// Settings AllowDependentAnimations will affect whether animations are
// enabled application-wide, so we don't need to check it each time we
// want to create an animation.
@@ -1281,7 +1292,13 @@ namespace winrt::TerminalApp::implementation
return;
}
if (const auto p = CommandPalette(); p.Visibility() == Visibility::Visible && cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
if (const auto p = CommandPalette(); p.Visibility() == Visibility::Visible &&
cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{
p.Visibility(Visibility::Collapsed);
}
if (const auto p = AutoCompleteMenu(); p.Visibility() == Visibility::Visible &&
cmd.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{
p.Visibility(Visibility::Collapsed);
}
@@ -1437,6 +1454,8 @@ namespace winrt::TerminalApp::implementation
term.SetTaskbarProgress({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });
term.ConnectionStateChanged({ get_weak(), &TerminalPage::_ConnectionStateChangedHandler });
term.MenuChanged({ get_weak(), &TerminalPage::_ControlMenuChangedHandler });
}
// Method Description:
@@ -3911,4 +3930,46 @@ namespace winrt::TerminalApp::implementation
applicationState.DismissedMessages(std::move(messages));
}
winrt::fire_and_forget TerminalPage::_ControlMenuChangedHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
co_await winrt::resume_foreground(Dispatcher(), CoreDispatcherPriority::Normal);
auto control{ _GetActiveControl() };
if (!control)
co_return;
// May be able to fake this by not creating whole Commands for these
// actions, instead just binding them at the cmdpal layer (like tab item
// vs action item)
auto entries = control.MenuEntries();
auto commandsCollection = winrt::single_threaded_vector<Command>();
for (const auto& entry : entries)
{
SendInputArgs args{ entry.Input };
ActionAndArgs actionAndArgs{ ShortcutAction::SendInput, args };
Command command{};
command.ActionAndArgs(actionAndArgs);
command.Name(entry.Name);
commandsCollection.Append(command);
}
// CommandPalette has an internal margin of 8, so set to -4,-4 to position closer to the actual line
AutoCompleteMenu().PositionManually(Windows::Foundation::Point{ -4, -4 }, Windows::Foundation::Size{ 300, 300 });
// CommandPalette().EnableCommandPaletteMode(CommandPaletteLaunchMode::Action);
const til::point cursorPos{ control.CursorPositionInDips() };
const auto characterSize{ control.CharacterDimensions() };
// Position relative to the actual term control
AutoCompletePopup().HorizontalOffset(cursorPos.x);
AutoCompletePopup().VerticalOffset(cursorPos.y + characterSize.Height);
AutoCompletePopup().IsOpen(true);
// Make visible first, then set commands. Other way around and the list
// doesn't actually update the first time (weird)
AutoCompleteMenu().Visibility(commandsCollection.Size() > 0 ? Visibility::Visible : Visibility::Collapsed);
AutoCompleteMenu().SetCommands(commandsCollection);
}
}

View File

@@ -410,6 +410,7 @@ namespace winrt::TerminalApp::implementation
void _RunRestorePreviews();
void _PreviewColorScheme(const Microsoft::Terminal::Settings::Model::SetColorSchemeArgs& args);
void _PreviewAdjustOpacity(const Microsoft::Terminal::Settings::Model::AdjustOpacityArgs& args);
void _PreviewSendInput(const Microsoft::Terminal::Settings::Model::SendInputArgs& args);
winrt::Microsoft::Terminal::Settings::Model::Command _lastPreviewedCommand{ nullptr };
std::vector<std::function<void()>> _restorePreviewFuncs{};
@@ -438,6 +439,8 @@ namespace winrt::TerminalApp::implementation
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
winrt::fire_and_forget _ControlMenuChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);

View File

@@ -168,6 +168,18 @@
PreviewKeyDown="_KeyDownHandler"
Visibility="Collapsed" />
<Popup x:Name="AutoCompletePopup"
HorizontalOffset="200"
IsOpen="False"
ShouldConstrainToRootBounds="False"
VerticalOffset="200">
<local:CommandPalette x:Name="AutoCompleteMenu"
VerticalAlignment="Stretch"
PreviewKeyDown="_KeyDownHandler"
Visibility="Collapsed" />
</Popup>
<!--
A TeachingTip with IsLightDismissEnabled="True" will immediately
dismiss itself if the window is unfocused (In Xaml Islands). This is
@@ -199,4 +211,5 @@
</mux:TeachingTip.Content>
</mux:TeachingTip>
</Grid>
</Page>

View File

@@ -108,6 +108,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnTerminalTaskbarProgressChanged = std::bind(&ControlCore::_terminalTaskbarProgressChanged, this);
_terminal->TaskbarProgressChangedCallback(pfnTerminalTaskbarProgressChanged);
auto pfnMenuChanged = std::bind(&ControlCore::_terminalMenuChanged, this);
_terminal->MenuChangedCallback(pfnMenuChanged);
// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
@@ -190,6 +193,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
});
_updateMenu = std::make_shared<ThrottledFuncTrailing<>>(
_dispatcher,
UpdatePatternLocationsInterval,
[weakThis = get_weak()]() {
if (auto core{ weakThis.get() }; !core->_IsClosing())
{
core->_MenuChangedHandlers(*core, nullptr);
}
});
UpdateSettings(settings, unfocusedAppearance);
}
@@ -1206,6 +1219,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_TaskbarProgressChangedHandlers(*this, nullptr);
}
void ControlCore::_terminalMenuChanged()
{
_updateMenu->Run();
// _MenuChangedHandlers(*this, nullptr);
}
bool ControlCore::HasSelection() const
{
return _terminal->IsSelectionActive();
@@ -1695,4 +1714,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// transparency, or our acrylic, or our image.
return Opacity() < 1.0f || UseAcrylic() || !_settings->BackgroundImage().empty();
}
static Windows::Foundation::Collections::IVector<Control::MenuEntry> _internalMenuToWinRT(const std::vector<DispatchTypes::MenuEntry>& menu)
{
auto v = winrt::single_threaded_observable_vector<Control::MenuEntry>();
for (const auto& entry : menu)
{
Control::MenuEntry e{};
e.Name = winrt::hstring(entry._name);
e.Comment = winrt::hstring(entry._comment);
e.Input = winrt::hstring(entry._input);
v.Append(e);
}
return v;
}
Windows::Foundation::Collections::IVector<Control::MenuEntry> ControlCore::MenuEntries() const
{
return _internalMenuToWinRT(_terminal->GetMenu());
}
}

View File

@@ -111,6 +111,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
int BufferHeight() const;
bool BracketedPasteEnabled() const noexcept;
Windows::Foundation::Collections::IVector<Control::MenuEntry> MenuEntries() const;
#pragma endregion
#pragma region ITerminalInput
@@ -192,6 +195,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TYPED_EVENT(TransparencyChanged, IInspectable, Control::TransparencyChangedEventArgs);
TYPED_EVENT(ReceivedOutput, IInspectable, IInspectable);
TYPED_EVENT(FoundMatch, IInspectable, Control::FoundResultsArgs);
TYPED_EVENT(MenuChanged, IInspectable, IInspectable);
// clang-format on
private:
@@ -239,6 +243,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
std::shared_ptr<ThrottledFuncTrailing<>> _updateMenu;
winrt::fire_and_forget _asyncCloseConnection();
@@ -259,6 +264,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const int bufferSize);
void _terminalCursorPositionChanged();
void _terminalTaskbarProgressChanged();
void _terminalMenuChanged();
#pragma endregion
#pragma region RendererCallbacks

View File

@@ -120,6 +120,7 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, TransparencyChangedEventArgs> TransparencyChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> ReceivedOutput;
event Windows.Foundation.TypedEventHandler<Object, FoundResultsArgs> FoundMatch;
event Windows.Foundation.TypedEventHandler<Object, Object> MenuChanged;
};
}

View File

@@ -3,6 +3,14 @@
namespace Microsoft.Terminal.Control
{
struct MenuEntry
{
String Name;
String Comment;
String Input;
};
// These are properties of the TerminalCore that should be queryable by the
// rest of the app.
interface ICoreState
@@ -24,5 +32,8 @@ namespace Microsoft.Terminal.Control
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
Microsoft.Terminal.Core.Scheme ColorScheme { get; set; };
IVector<MenuEntry> MenuEntries { get; };
};
}

View File

@@ -470,4 +470,19 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TSFInputControl::_formatUpdatingHandler(CoreTextEditContext sender, CoreTextFormatUpdatingEventArgs const& /*args*/)
{
}
void TSFInputControl::ManuallyDisplayText(const winrt::hstring& text)
{
_focused = !text.empty();
Canvas().Visibility(text.empty() ? Visibility::Collapsed : Visibility::Visible);
_inputBuffer.clear();
// _editContext.NotifyFocusLeave();
_activeTextStart = 0;
_inComposition = false;
TextBlock().Text(text);
TextBlock().UpdateLayout();
TryRedrawCanvas();
}
}

View File

@@ -40,6 +40,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ClearBuffer();
void TryRedrawCanvas();
void ManuallyDisplayText(const winrt::hstring& text);
void Close();
// -------------------------------- WinRT Events ---------------------------------

View File

@@ -31,6 +31,9 @@ namespace Microsoft.Terminal.Control
void ClearBuffer();
void TryRedrawCanvas();
void ManuallyDisplayText(String text);
void Close();
}
}

View File

@@ -322,6 +322,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - <none>
void TermControl::SendInput(const winrt::hstring& wstr)
{
PreviewInput(L"");
_core.SendInput(wstr);
}
void TermControl::ClearBuffer(Control::ClearBufferType clearType)
@@ -2777,4 +2778,40 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
Microsoft::Terminal::Core::Point TermControl::CursorPositionInDips()
{
// const auto cursorPosition{ _core.CursorPosition() };
const til::point cursorPos{ _core.CursorPosition() };
const til::size fontSize{ til::math::flooring, CharacterDimensions() };
// Convert text buffer cursor position to client coordinate position
// within the window. This point is in _pixels_
const til::point clientCursorPos{ cursorPos * fontSize };
// Get scale factor for view
const double scaleFactor = DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel();
const til::point clientCursorInDips{ til::math::flooring, clientCursorPos.x / scaleFactor, clientCursorPos.y / scaleFactor };
// + SwapChainPanel().Margin().Top
auto padding{ GetPadding() };
til::point relativeToOrigin{ til::math::flooring,
clientCursorInDips.x + padding.Left,
clientCursorInDips.y + padding.Top
};
return relativeToOrigin.to_core_point();
}
Windows::Foundation::Collections::IVector<Control::MenuEntry> TermControl::MenuEntries() const
{
return _core.MenuEntries();
}
void TermControl::PreviewInput(const winrt::hstring& text)
{
TSFInputControl().ManuallyDisplayText(text);
}
}

View File

@@ -41,6 +41,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Windows::Foundation::Size CharacterDimensions() const;
Windows::Foundation::Size MinimumSize();
float SnapDimensionToGrid(const bool widthOrHeight, const float dimension);
Microsoft::Terminal::Core::Point CursorPositionInDips();
void PreviewInput(const winrt::hstring& text);
#pragma region ICoreState
const uint64_t TaskbarState() const noexcept;
@@ -59,6 +61,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool BracketedPasteEnabled() const noexcept;
double BackgroundOpacity() const;
Windows::Foundation::Collections::IVector<Control::MenuEntry> MenuEntries() const;
#pragma endregion
void ScrollViewport(int viewTop);
@@ -121,6 +126,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
PROJECTED_FORWARDED_TYPED_EVENT(TabColorChanged, IInspectable, IInspectable, _core, TabColorChanged);
PROJECTED_FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable, _core, TaskbarProgressChanged);
PROJECTED_FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable, _core, ConnectionStateChanged);
PROJECTED_FORWARDED_TYPED_EVENT(MenuChanged , IInspectable, IInspectable, _core, MenuChanged);
PROJECTED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs, _interactivity, PasteFromClipboard);

View File

@@ -40,6 +40,7 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> ReadOnlyChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FocusFollowMouseRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> MenuChanged;
event Windows.Foundation.TypedEventHandler<TermControl, Windows.UI.Xaml.RoutedEventArgs> Initialized;
// This is an event handler forwarder for the underlying connection.
@@ -81,5 +82,9 @@ namespace Microsoft.Terminal.Control
// opacity set by the settings should call this instead.
Double BackgroundOpacity { get; };
Microsoft.Terminal.Core.Point CursorPositionInDips { get; };
void PreviewInput(String text);
}
}

View File

@@ -69,6 +69,12 @@ namespace Microsoft::Terminal::Core
virtual void PushGraphicsRendition(const ::Microsoft::Console::VirtualTerminal::VTParameters options) = 0;
virtual void PopGraphicsRendition() = 0;
virtual void UseAlternateScreenBuffer() = 0;
virtual void UseMainScreenBuffer() = 0;
virtual void ClearMenu() = 0;
virtual void AddToMenu(const Microsoft::Console::VirtualTerminal::DispatchTypes::MenuEntry& menu) = 0;
protected:
ITerminalApi() = default;
};

View File

@@ -40,6 +40,7 @@ Terminal::Terminal() :
_mutableViewport{ Viewport::Empty() },
_title{},
_pfnWriteInput{ nullptr },
_altBuffer{ nullptr },
_scrollOffset{ 0 },
_snapOnInput{ true },
_altGrAliasing{ true },
@@ -85,7 +86,7 @@ void Terminal::Create(COORD viewportSize, SHORT scrollbackLines, Renderer& rende
Utils::ClampToShortMax(viewportSize.Y + scrollbackLines, 1) };
const TextAttribute attr{};
const UINT cursorSize = 12;
_buffer = std::make_unique<TextBuffer>(bufferSize, attr, cursorSize, true, renderer);
_mainBuffer = std::make_unique<TextBuffer>(bufferSize, attr, cursorSize, true, renderer);
}
// Method Description:
@@ -147,15 +148,17 @@ void Terminal::UpdateSettings(ICoreSettings settings)
// size is smaller than where the mutable viewport currently is, we'll want
// to make sure to rotate the buffer contents upwards, so the mutable viewport
// remains at the bottom of the buffer.
if (_buffer)
// Regenerate the pattern tree for the new buffer size
if (_mainBuffer)
{
// Clear the patterns first
_buffer->ClearPatternRecognizers();
_mainBuffer->ClearPatternRecognizers();
if (settings.DetectURLs())
{
// Add regex pattern recognizers to the buffer
// For now, we only add the URI regex pattern
_hyperlinkPatternId = _buffer->AddPatternRecognizer(linkPattern);
_hyperlinkPatternId = _mainBuffer->AddPatternRecognizer(linkPattern);
UpdatePatternsUnderLock();
}
else
@@ -213,9 +216,12 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
break;
}
if (_buffer)
// We're checking if the main buffer exists here, but then setting the
// appearance of the active one. If the main buffer exists, then at least
// one buffer exists and _activeBuffer() will work
if (_mainBuffer)
{
_buffer->GetCursor().SetStyle(appearance.CursorHeight(), cursorShape);
_activeBuffer().GetCursor().SetStyle(appearance.CursorHeight(), cursorShape);
}
_defaultCursorShape = cursorShape;
@@ -231,12 +237,38 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
// appropriate HRESULT for failing to resize.
[[nodiscard]] HRESULT Terminal::UserResize(const COORD viewportSize) noexcept
{
const auto oldDimensions = _mutableViewport.Dimensions();
const auto oldDimensions = _GetMutableViewport().Dimensions();
if (viewportSize == oldDimensions)
{
return S_FALSE;
}
// Shortcut: if we're in the alt buffer, just resize the
// alt buffer and put off resizing the main buffer till we switch back. Fortunately, this is easy. We don't need to
// worry about the viewport and scrollback at all! The alt buffer never has
// any scrollback, so we just need to resize it and presto, we're done.
if (_inAltBuffer())
{
// stash this resize for the future.
_deferredResize = til::size{ viewportSize };
_altBuffer->GetCursor().StartDeferDrawing();
// we're capturing `this` here because when we exit, we want to EndDefer on the (newly created) active buffer.
auto endDefer = wil::scope_exit([this]() noexcept { _altBuffer->GetCursor().EndDeferDrawing(); });
// GH#3494: We don't need to reflow the alt buffer. Apps that use the
// alt buffer will redraw themselves. This prevents graphical artifacts.
//
// This is consistent with VTE
RETURN_IF_FAILED(_altBuffer->ResizeTraditional(viewportSize));
// Since the _mutableViewport is no longer the size of the actual
// viewport, then update our _altBufferSize tracker we're using to help
// us out here.
_altBufferSize = til::size{ viewportSize };
return S_OK;
}
const auto dx = ::base::ClampSub(viewportSize.X, oldDimensions.X);
const short newBufferHeight = ::base::ClampAdd(viewportSize.Y, _scrollbackLines);
@@ -252,9 +284,9 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
const bool originalOffsetWasZero = _scrollOffset == 0;
// skip any drawing updates that might occur until we swap _buffer with the new buffer or if we exit early.
_buffer->GetCursor().StartDeferDrawing();
// we're capturing _buffer by reference here because when we exit, we want to EndDefer on the current active buffer.
auto endDefer = wil::scope_exit([&]() noexcept { _buffer->GetCursor().EndDeferDrawing(); });
_mainBuffer->GetCursor().StartDeferDrawing();
// we're capturing `this` here because when we exit, we want to EndDefer on the (newly created) active buffer.
auto endDefer = wil::scope_exit([this]() noexcept { _mainBuffer->GetCursor().EndDeferDrawing(); });
// First allocate a new text buffer to take the place of the current one.
std::unique_ptr<TextBuffer> newTextBuffer;
@@ -265,13 +297,14 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
// but after the resize, we'll want to make sure that the new buffer's
// current attributes (the ones used for printing new text) match the
// old buffer's.
const auto oldBufferAttributes = _buffer->GetCurrentAttributes();
const auto oldBufferAttributes = _mainBuffer->GetCurrentAttributes();
newTextBuffer = std::make_unique<TextBuffer>(bufferSize,
TextAttribute{},
0, // temporarily set size to 0 so it won't render.
_buffer->IsActiveBuffer(),
_buffer->GetRenderer());
_mainBuffer->IsActiveBuffer(),
_mainBuffer->GetRenderer());
// start defer drawing on the new buffer
newTextBuffer->GetCursor().StartDeferDrawing();
// Build a PositionInformation to track the position of both the top of
@@ -289,7 +322,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
oldRows.visibleViewportTop = newVisibleTop;
const std::optional<short> oldViewStart{ oldViewportTop };
RETURN_IF_FAILED(TextBuffer::Reflow(*_buffer.get(),
RETURN_IF_FAILED(TextBuffer::Reflow(*_mainBuffer.get(),
*newTextBuffer.get(),
_mutableViewport,
{ oldRows }));
@@ -405,7 +438,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
_mutableViewport = Viewport::FromDimensions({ 0, proposedTop }, viewportSize);
_buffer.swap(newTextBuffer);
_mainBuffer.swap(newTextBuffer);
// GH#3494: Maintain scrollbar position during resize
// Make sure that we don't scroll past the mutableViewport at the bottom of the buffer
@@ -420,7 +453,7 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
// GH#5029 - make sure to InvalidateAll here, so that we'll paint the entire visible viewport.
try
{
_buffer->TriggerRedrawAll();
_activeBuffer().TriggerRedrawAll();
}
CATCH_LOG();
_NotifyScrollEvent();
@@ -432,7 +465,7 @@ void Terminal::Write(std::wstring_view stringView)
{
auto lock = LockForWriting();
auto& cursor = _buffer->GetCursor();
auto& cursor = _activeBuffer().GetCursor();
const til::point cursorPosBefore{ cursor.GetPosition() };
_stateMachine->ProcessString(stringView);
@@ -502,10 +535,10 @@ bool Terminal::IsTrackingMouseInput() const noexcept
// - The position
std::wstring Terminal::GetHyperlinkAtPosition(const COORD position)
{
auto attr = _buffer->GetCellDataAt(_ConvertToBufferCell(position))->TextAttr();
auto attr = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(position))->TextAttr();
if (attr.IsHyperlink())
{
auto uri = _buffer->GetHyperlinkUriFromId(attr.GetHyperlinkId());
auto uri = _activeBuffer().GetHyperlinkUriFromId(attr.GetHyperlinkId());
return uri;
}
// also look through our known pattern locations in our pattern interval tree
@@ -516,8 +549,8 @@ std::wstring Terminal::GetHyperlinkAtPosition(const COORD position)
const auto end = result->stop;
std::wstring uri;
const auto startIter = _buffer->GetCellDataAt(_ConvertToBufferCell(start.to_win32_coord()));
const auto endIter = _buffer->GetCellDataAt(_ConvertToBufferCell(end.to_win32_coord()));
const auto startIter = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(start.to_win32_coord()));
const auto endIter = _activeBuffer().GetCellDataAt(_ConvertToBufferCell(end.to_win32_coord()));
for (auto iter = startIter; iter != endIter; ++iter)
{
uri += iter->Chars();
@@ -535,7 +568,7 @@ std::wstring Terminal::GetHyperlinkAtPosition(const COORD position)
// - The hyperlink ID
uint16_t Terminal::GetHyperlinkIdAtPosition(const COORD position)
{
return _buffer->GetCellDataAt(_ConvertToBufferCell(position))->TextAttr().GetHyperlinkId();
return _activeBuffer().GetCellDataAt(_ConvertToBufferCell(position))->TextAttr().GetHyperlinkId();
}
// Method description:
@@ -732,26 +765,26 @@ void Terminal::_InvalidateFromCoords(const COORD start, const COORD end)
if (start.Y == end.Y)
{
SMALL_RECT region{ start.X, start.Y, end.X, end.Y };
_buffer->TriggerRedraw(Viewport::FromInclusive(region));
_activeBuffer().TriggerRedraw(Viewport::FromInclusive(region));
}
else
{
const auto rowSize = gsl::narrow<SHORT>(_buffer->GetRowByOffset(0).size());
const auto rowSize = gsl::narrow<SHORT>(_activeBuffer().GetRowByOffset(0).size());
// invalidate the first line
SMALL_RECT region{ start.X, start.Y, gsl::narrow<short>(rowSize - 1), gsl::narrow<short>(start.Y) };
_buffer->TriggerRedraw(Viewport::FromInclusive(region));
_activeBuffer().TriggerRedraw(Viewport::FromInclusive(region));
if ((end.Y - start.Y) > 1)
{
// invalidate the lines in between the first and last line
region = SMALL_RECT{ 0, start.Y + 1, gsl::narrow<short>(rowSize - 1), gsl::narrow<short>(end.Y - 1) };
_buffer->TriggerRedraw(Viewport::FromInclusive(region));
_activeBuffer().TriggerRedraw(Viewport::FromInclusive(region));
}
// invalidate the last line
region = SMALL_RECT{ 0, end.Y, end.X, end.Y };
_buffer->TriggerRedraw(Viewport::FromInclusive(region));
_activeBuffer().TriggerRedraw(Viewport::FromInclusive(region));
}
}
@@ -897,41 +930,52 @@ WORD Terminal::_TakeVirtualKeyFromLastKeyEvent(const WORD scanCode) noexcept
Viewport Terminal::_GetMutableViewport() const noexcept
{
return _mutableViewport;
// GH#3493: if we're in the alt buffer, then it's possible that the mutable
// viewport's size hasn't been updated yet. In that case, use the
// temporarily stashed _altBufferSize instead.
return _inAltBuffer() ? Viewport::FromDimensions(_altBufferSize.to_win32_coord()) :
_mutableViewport;
}
short Terminal::GetBufferHeight() const noexcept
{
return _mutableViewport.BottomExclusive();
return _GetMutableViewport().BottomExclusive();
}
// ViewStartIndex is also the length of the scrollback
int Terminal::ViewStartIndex() const noexcept
{
return _mutableViewport.Top();
return _inAltBuffer() ? 0 : _mutableViewport.Top();
}
int Terminal::ViewEndIndex() const noexcept
{
return _mutableViewport.BottomInclusive();
return _inAltBuffer() ? _altBufferSize.height : _mutableViewport.BottomInclusive();
}
// _VisibleStartIndex is the first visible line of the buffer
int Terminal::_VisibleStartIndex() const noexcept
{
return std::max(0, ViewStartIndex() - _scrollOffset);
return _inAltBuffer() ? ViewStartIndex() :
std::max(0, ViewStartIndex() - _scrollOffset);
}
int Terminal::_VisibleEndIndex() const noexcept
{
return std::max(0, ViewEndIndex() - _scrollOffset);
return _inAltBuffer() ? ViewEndIndex() :
std::max(0, ViewEndIndex() - _scrollOffset);
}
Viewport Terminal::_GetVisibleViewport() const noexcept
{
// GH#3493: if we're in the alt buffer, then it's possible that the mutable
// viewport's size hasn't been updated yet. In that case, use the
// temporarily stashed _altBufferSize instead.
const COORD origin{ 0, gsl::narrow<short>(_VisibleStartIndex()) };
const COORD size{ _inAltBuffer() ? _altBufferSize.to_win32_coord() :
_mutableViewport.Dimensions() };
return Viewport::FromDimensions(origin,
_mutableViewport.Dimensions());
size);
}
// Writes a string of text to the buffer, then moves the cursor (and viewport)
@@ -944,7 +988,7 @@ Viewport Terminal::_GetVisibleViewport() const noexcept
// I had to make a bunch of hacks to get Japanese and emoji to work-ish.
void Terminal::_WriteBuffer(const std::wstring_view& stringView)
{
auto& cursor = _buffer->GetCursor();
auto& cursor = _activeBuffer().GetCursor();
// Defer the cursor drawing while we are iterating the string, for a better performance.
// We can not waste time displaying a cursor event when we know more text is coming right behind it.
@@ -963,8 +1007,8 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView)
// from the stringView to form a single code point.
const auto isSurrogate = wch >= 0xD800 && wch <= 0xDFFF;
const auto view = stringView.substr(i, isSurrogate ? 2 : 1);
const OutputCellIterator it{ view, _buffer->GetCurrentAttributes() };
const auto end = _buffer->Write(it);
const OutputCellIterator it{ view, _activeBuffer().GetCurrentAttributes() };
const auto end = _activeBuffer().Write(it);
const auto cellDistance = end.GetCellDistance(it);
const auto inputDistance = end.GetInputDistance(it);
@@ -1006,7 +1050,7 @@ void Terminal::_WriteBuffer(const std::wstring_view& stringView)
// Notify UIA of new text.
// It's important to do this here instead of in TextBuffer, because here you have access to the entire line of text,
// whereas TextBuffer writes it one character at a time via the OutputCellIterator.
_buffer->TriggerNewTextNotification(stringView);
_activeBuffer().TriggerNewTextNotification(stringView);
cursor.EndDeferDrawing();
}
@@ -1015,8 +1059,8 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
{
#pragma warning(suppress : 26496) // cpp core checks wants this const but it's modified below.
auto proposedCursorPosition = proposedPosition;
auto& cursor = _buffer->GetCursor();
const Viewport bufferSize = _buffer->GetSize();
auto& cursor = _activeBuffer().GetCursor();
const Viewport bufferSize = _activeBuffer().GetSize();
// If we're about to scroll past the bottom of the buffer, instead cycle the
// buffer.
@@ -1026,7 +1070,7 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
{
for (auto dy = 0; dy < newRows; dy++)
{
_buffer->IncrementCircularBuffer();
_activeBuffer().IncrementCircularBuffer();
proposedCursorPosition.Y--;
rowsPushedOffTopOfBuffer++;
@@ -1069,7 +1113,8 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
if (scrollAmount > 0)
{
const auto newViewTop = std::max(0, proposedCursorPosition.Y - (_mutableViewport.Height() - 1));
if (newViewTop != _mutableViewport.Top())
// In the alt buffer, we never need to adjust _mutableViewport, which is the viewport of the main buffer.
if (!_inAltBuffer() && newViewTop != _mutableViewport.Top())
{
_mutableViewport = Viewport::FromDimensions({ 0, gsl::narrow<short>(newViewTop) },
_mutableViewport.Dimensions());
@@ -1079,7 +1124,7 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
// If the viewport moved, or we circled the buffer, we might need to update
// our _scrollOffset
if (updatedViewport || newRows != 0)
if (!_inAltBuffer() && (updatedViewport || newRows != 0))
{
const auto oldScrollOffset = _scrollOffset;
@@ -1093,7 +1138,7 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
// Clamp the range to make sure that we don't scroll way off the top of the buffer
_scrollOffset = std::clamp(_scrollOffset,
0,
_buffer->GetSize().Height() - _mutableViewport.Height());
_activeBuffer().GetSize().Height() - _mutableViewport.Height());
// If the new scroll offset is different, then we'll still want to raise a scroll event
updatedViewport = updatedViewport || (oldScrollOffset != _scrollOffset);
@@ -1111,12 +1156,17 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
// That didn't change the viewport and therefore the TriggerScroll(void)
// method can't detect the delta on its own.
COORD delta{ 0, gsl::narrow_cast<short>(-rowsPushedOffTopOfBuffer) };
_buffer->TriggerScroll(delta);
_activeBuffer().TriggerScroll(delta);
}
}
void Terminal::UserScrollViewport(const int viewTop)
{
if (_inAltBuffer())
{
return;
}
// we're going to modify state here that the renderer could be reading.
auto lock = LockForWriting();
@@ -1130,7 +1180,7 @@ void Terminal::UserScrollViewport(const int viewTop)
// We can use the void variant of TriggerScroll here because
// we adjusted the viewport so it can detect the difference
// from the previous frame drawn.
_buffer->TriggerScroll();
_activeBuffer().TriggerScroll();
}
int Terminal::GetScrollOffset() noexcept
@@ -1218,6 +1268,11 @@ void Microsoft::Terminal::Core::Terminal::TaskbarProgressChangedCallback(std::fu
_pfnTaskbarProgressChanged.swap(pfn);
}
void Microsoft::Terminal::Core::Terminal::MenuChangedCallback(std::function<void()> pfn) noexcept
{
_pfnMenuChanged.swap(pfn);
}
// Method Description:
// - Sets the cursor to be currently on. On/Off is tracked independently of
// cursor visibility (hidden/visible). On/off is controlled by the cursor
@@ -1229,12 +1284,12 @@ void Microsoft::Terminal::Core::Terminal::TaskbarProgressChangedCallback(std::fu
void Terminal::SetCursorOn(const bool isOn)
{
auto lock = LockForWriting();
_buffer->GetCursor().SetIsOn(isOn);
_activeBuffer().GetCursor().SetIsOn(isOn);
}
bool Terminal::IsCursorBlinkingAllowed() const noexcept
{
const auto& cursor = _buffer->GetCursor();
const auto& cursor = _activeBuffer().GetCursor();
return cursor.IsBlinkingAllowed();
}
@@ -1246,7 +1301,7 @@ bool Terminal::IsCursorBlinkingAllowed() const noexcept
void Terminal::UpdatePatternsUnderLock() noexcept
{
auto oldTree = _patternIntervalTree;
_patternIntervalTree = _buffer->GetPatterns(_VisibleStartIndex(), _VisibleEndIndex());
_patternIntervalTree = _activeBuffer().GetPatterns(_VisibleStartIndex(), _VisibleEndIndex());
_InvalidatePatternTree(oldTree);
_InvalidatePatternTree(_patternIntervalTree);
}
@@ -1343,3 +1398,18 @@ void Terminal::ApplyScheme(const Scheme& colorScheme)
_renderSettings.MakeAdjustedColorArray();
}
bool Terminal::_inAltBuffer() const noexcept
{
return _altBuffer != nullptr;
}
TextBuffer& Terminal::_activeBuffer() const noexcept
{
return _inAltBuffer() ? *_altBuffer : *_mainBuffer;
}
const std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::MenuEntry>& Terminal::GetMenu() const
{
return _menu;
}

View File

@@ -93,6 +93,7 @@ public:
RenderSettings& GetRenderSettings() noexcept { return _renderSettings; };
const RenderSettings& GetRenderSettings() const noexcept { return _renderSettings; };
const std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::MenuEntry>& GetMenu() const;
#pragma region ITerminalApi
// These methods are defined in TerminalApi.cpp
@@ -138,6 +139,13 @@ public:
void PushGraphicsRendition(const ::Microsoft::Console::VirtualTerminal::VTParameters options) override;
void PopGraphicsRendition() override;
void UseAlternateScreenBuffer() override;
void UseMainScreenBuffer() override;
// void InvokeMenu(const std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::MenuEntry>& menu) override;
void ClearMenu();
void AddToMenu(const Microsoft::Console::VirtualTerminal::DispatchTypes::MenuEntry& menu);
#pragma endregion
#pragma region ITerminalInput
@@ -207,6 +215,7 @@ public:
void SetCursorPositionChangedCallback(std::function<void()> pfn) noexcept;
void SetBackgroundCallback(std::function<void(const til::color)> pfn) noexcept;
void TaskbarProgressChangedCallback(std::function<void()> pfn) noexcept;
void MenuChangedCallback(std::function<void()> pfn) noexcept;
void SetCursorOn(const bool isOn);
bool IsCursorBlinkingAllowed() const noexcept;
@@ -274,6 +283,7 @@ private:
std::function<void()> _pfnCursorPositionChanged;
std::function<void(const std::optional<til::color>)> _pfnTabColorChanged;
std::function<void()> _pfnTaskbarProgressChanged;
std::function<void()> _pfnMenuChanged;
RenderSettings _renderSettings;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
@@ -321,10 +331,14 @@ private:
// TODO: These members are not shared by an alt-buffer. They should be
// encapsulated, such that a Terminal can have both a main and alt buffer.
std::unique_ptr<TextBuffer> _buffer;
std::unique_ptr<TextBuffer> _mainBuffer;
std::unique_ptr<TextBuffer> _altBuffer;
Microsoft::Console::Types::Viewport _mutableViewport;
SHORT _scrollbackLines;
til::size _altBufferSize;
std::optional<til::size> _deferredResize{ std::nullopt };
// _scrollOffset is the number of lines above the viewport that are currently visible
// If _scrollOffset is 0, then the visible region of the buffer is the viewport.
int _scrollOffset;
@@ -353,6 +367,8 @@ private:
};
std::optional<KeyEventCodes> _lastKeyEventCodes;
std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::MenuEntry> _menu;
static WORD _ScanCodeFromVirtualKey(const WORD vkey) noexcept;
static WORD _VirtualKeyFromScanCode(const WORD scanCode) noexcept;
static WORD _VirtualKeyFromCharacter(const wchar_t ch) noexcept;
@@ -375,6 +391,9 @@ private:
void _NotifyTerminalCursorPositionChanged() noexcept;
bool _inAltBuffer() const noexcept;
TextBuffer& _activeBuffer() const noexcept;
#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
std::vector<SMALL_RECT> _GetSelectionRects() const noexcept;

View File

@@ -18,7 +18,7 @@ void Terminal::PrintString(std::wstring_view stringView)
TextAttribute Terminal::GetTextAttributes() const
{
return _buffer->GetCurrentAttributes();
return _activeBuffer().GetCurrentAttributes();
}
bool Terminal::ReturnResponse(std::wstring_view responseString)
@@ -33,12 +33,12 @@ bool Terminal::ReturnResponse(std::wstring_view responseString)
void Terminal::SetTextAttributes(const TextAttribute& attrs)
{
_buffer->SetCurrentAttributes(attrs);
_activeBuffer().SetCurrentAttributes(attrs);
}
Viewport Terminal::GetBufferSize()
{
return _buffer->GetSize();
return _activeBuffer().GetSize();
}
void Terminal::SetCursorPosition(short x, short y)
@@ -49,12 +49,12 @@ void Terminal::SetCursorPosition(short x, short y)
const short absoluteY = viewOrigin.Y + y;
COORD newPos{ absoluteX, absoluteY };
viewport.Clamp(newPos);
_buffer->GetCursor().SetPosition(newPos);
_activeBuffer().GetCursor().SetPosition(newPos);
}
COORD Terminal::GetCursorPosition()
{
const auto absoluteCursorPos = _buffer->GetCursor().GetPosition();
const auto absoluteCursorPos = _activeBuffer().GetCursor().GetPosition();
const auto viewport = _GetMutableViewport();
const auto viewOrigin = viewport.Origin();
const short relativeX = absoluteCursorPos.X - viewOrigin.X;
@@ -73,11 +73,11 @@ COORD Terminal::GetCursorPosition()
// - <none>
void Terminal::CursorLineFeed(const bool withReturn)
{
auto cursorPos = _buffer->GetCursor().GetPosition();
auto cursorPos = _activeBuffer().GetCursor().GetPosition();
// since we explicitly just moved down a row, clear the wrap status on the
// row we just came from
_buffer->GetRowByOffset(cursorPos.Y).SetWrapForced(false);
_activeBuffer().GetRowByOffset(cursorPos.Y).SetWrapForced(false);
cursorPos.Y++;
if (withReturn)
@@ -101,10 +101,12 @@ void Terminal::DeleteCharacter(const size_t count)
{
SHORT dist;
THROW_IF_FAILED(SizeTToShort(count, &dist));
const auto cursorPos = _buffer->GetCursor().GetPosition();
const auto cursorPos = _activeBuffer().GetCursor().GetPosition();
const auto copyToPos = cursorPos;
const COORD copyFromPos{ cursorPos.X + dist, cursorPos.Y };
const auto sourceWidth = _mutableViewport.RightExclusive() - copyFromPos.X;
const auto viewport = _GetMutableViewport();
const auto sourceWidth = viewport.RightExclusive() - copyFromPos.X;
SHORT width;
THROW_IF_FAILED(UIntToShort(sourceWidth, &width));
@@ -121,8 +123,8 @@ void Terminal::DeleteCharacter(const size_t count)
// Iterate over the source cell data and copy it over to the target
do
{
const auto data = OutputCell(*(_buffer->GetCellDataAt(sourcePos)));
_buffer->Write(OutputCellIterator({ &data, 1 }), targetPos);
const auto data = OutputCell(*(_activeBuffer().GetCellDataAt(sourcePos)));
_activeBuffer().Write(OutputCellIterator({ &data, 1 }), targetPos);
} while (source.WalkInBounds(sourcePos, walkDirection) && target.WalkInBounds(targetPos, walkDirection));
}
@@ -143,10 +145,11 @@ void Terminal::InsertCharacter(const size_t count)
// TODO: Github issue #2163
SHORT dist;
THROW_IF_FAILED(SizeTToShort(count, &dist));
const auto cursorPos = _buffer->GetCursor().GetPosition();
const auto cursorPos = _activeBuffer().GetCursor().GetPosition();
const auto copyFromPos = cursorPos;
const COORD copyToPos{ cursorPos.X + dist, cursorPos.Y };
const auto sourceWidth = _mutableViewport.RightExclusive() - copyFromPos.X;
const auto viewport = _GetMutableViewport();
const auto sourceWidth = viewport.RightExclusive() - copyFromPos.X;
SHORT width;
THROW_IF_FAILED(UIntToShort(sourceWidth, &width));
@@ -164,21 +167,21 @@ void Terminal::InsertCharacter(const size_t count)
// Iterate over the source cell data and copy it over to the target
do
{
const auto data = OutputCell(*(_buffer->GetCellDataAt(sourcePos)));
_buffer->Write(OutputCellIterator({ &data, 1 }), targetPos);
const auto data = OutputCell(*(_activeBuffer().GetCellDataAt(sourcePos)));
_activeBuffer().Write(OutputCellIterator({ &data, 1 }), targetPos);
} while (source.WalkInBounds(sourcePos, walkDirection) && target.WalkInBounds(targetPos, walkDirection));
const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _buffer->GetCurrentAttributes(), dist);
_buffer->Write(eraseIter, cursorPos);
const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _activeBuffer().GetCurrentAttributes(), dist);
_activeBuffer().Write(eraseIter, cursorPos);
}
void Terminal::EraseCharacters(const size_t numChars)
{
const auto absoluteCursorPos = _buffer->GetCursor().GetPosition();
const auto absoluteCursorPos = _activeBuffer().GetCursor().GetPosition();
const auto viewport = _GetMutableViewport();
const short distanceToRight = viewport.RightExclusive() - absoluteCursorPos.X;
const short fillLimit = std::min(static_cast<short>(numChars), distanceToRight);
const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _buffer->GetCurrentAttributes(), fillLimit);
_buffer->Write(eraseIter, absoluteCursorPos);
const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _activeBuffer().GetCurrentAttributes(), fillLimit);
_activeBuffer().Write(eraseIter, absoluteCursorPos);
}
// Method description:
@@ -193,7 +196,7 @@ void Terminal::EraseCharacters(const size_t numChars)
// - true if succeeded, false otherwise
bool Terminal::EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType)
{
const auto cursorPos = _buffer->GetCursor().GetPosition();
const auto cursorPos = _activeBuffer().GetCursor().GetPosition();
const auto viewport = _GetMutableViewport();
COORD startPos = { 0 };
startPos.Y = cursorPos.Y;
@@ -218,10 +221,10 @@ bool Terminal::EraseInLine(const ::Microsoft::Console::VirtualTerminal::Dispatch
return false;
}
const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _buffer->GetCurrentAttributes(), nlength);
const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _activeBuffer().GetCurrentAttributes(), nlength);
// Explicitly turn off end-of-line wrap-flag-setting when erasing cells.
_buffer->Write(eraseIter, startPos, false);
_activeBuffer().Write(eraseIter, startPos, false);
return true;
}
@@ -236,22 +239,33 @@ bool Terminal::EraseInLine(const ::Microsoft::Console::VirtualTerminal::Dispatch
bool Terminal::EraseInDisplay(const DispatchTypes::EraseType eraseType)
{
// Store the relative cursor position so we can restore it later after we move the viewport
const auto cursorPos = _buffer->GetCursor().GetPosition();
const auto cursorPos = _activeBuffer().GetCursor().GetPosition();
#pragma warning(suppress : 26496) // This is written by ConvertToOrigin, cpp core checks is wrong saying it should be const.
auto relativeCursor = cursorPos;
_mutableViewport.ConvertToOrigin(&relativeCursor);
const auto viewport = _GetMutableViewport();
viewport.ConvertToOrigin(&relativeCursor);
// Initialize the new location of the viewport
// the top and bottom parameters are determined by the eraseType
SMALL_RECT newWin;
newWin.Left = _mutableViewport.Left();
newWin.Right = _mutableViewport.RightExclusive();
newWin.Left = viewport.Left();
newWin.Right = viewport.RightExclusive();
if (eraseType == DispatchTypes::EraseType::All)
{
// If we're in the alt buffer, take a shortcut. Just increment the buffer enough to cycle the whole thing out and start fresh. This
if (_inAltBuffer())
{
for (auto i = 0; i < viewport.Height(); i++)
{
_activeBuffer().IncrementCircularBuffer();
}
return true;
}
// In this case, we simply move the viewport down, effectively pushing whatever text was on the screen into the scrollback
// and thus 'erasing' the text visible to the user
const auto coordLastChar = _buffer->GetLastNonSpaceCharacter(_mutableViewport);
const auto coordLastChar = _activeBuffer().GetLastNonSpaceCharacter(viewport);
if (coordLastChar.X == 0 && coordLastChar.Y == 0)
{
// Nothing to clear, just return
@@ -261,38 +275,38 @@ bool Terminal::EraseInDisplay(const DispatchTypes::EraseType eraseType)
short sNewTop = coordLastChar.Y + 1;
// Increment the circular buffer only if the new location of the viewport would be 'below' the buffer
const short delta = (sNewTop + _mutableViewport.Height()) - (_buffer->GetSize().Height());
const short delta = (sNewTop + viewport.Height()) - (_activeBuffer().GetSize().Height());
for (auto i = 0; i < delta; i++)
{
_buffer->IncrementCircularBuffer();
_activeBuffer().IncrementCircularBuffer();
sNewTop--;
}
newWin.Top = sNewTop;
newWin.Bottom = sNewTop + _mutableViewport.Height();
newWin.Bottom = sNewTop + viewport.Height();
}
else if (eraseType == DispatchTypes::EraseType::Scrollback)
{
// We only want to erase the scrollback, and leave everything else on the screen as it is
// so we grab the text in the viewport and rotate it up to the top of the buffer
COORD scrollFromPos{ 0, 0 };
_mutableViewport.ConvertFromOrigin(&scrollFromPos);
_buffer->ScrollRows(scrollFromPos.Y, _mutableViewport.Height(), -scrollFromPos.Y);
viewport.ConvertFromOrigin(&scrollFromPos);
_activeBuffer().ScrollRows(scrollFromPos.Y, viewport.Height(), -scrollFromPos.Y);
// Since we only did a rotation, the text that was in the scrollback is now _below_ where we are going to move the viewport
// and we have to make sure we erase that text
const auto eraseStart = _mutableViewport.Height();
const auto eraseEnd = _buffer->GetLastNonSpaceCharacter(_mutableViewport).Y;
const auto eraseStart = viewport.Height();
const auto eraseEnd = _activeBuffer().GetLastNonSpaceCharacter(viewport).Y;
for (SHORT i = eraseStart; i <= eraseEnd; i++)
{
_buffer->GetRowByOffset(i).Reset(_buffer->GetCurrentAttributes());
_activeBuffer().GetRowByOffset(i).Reset(_activeBuffer().GetCurrentAttributes());
}
// Reset the scroll offset now because there's nothing for the user to 'scroll' to
_scrollOffset = 0;
newWin.Top = 0;
newWin.Bottom = _mutableViewport.Height();
newWin.Bottom = viewport.Height();
}
else
{
@@ -350,7 +364,7 @@ void Terminal::SetColorTableEntry(const size_t tableIndex, const COLORREF color)
}
// Repaint everything - the colors might have changed
_buffer->TriggerRedrawAll();
_activeBuffer().TriggerRedrawAll();
}
// Method Description:
@@ -412,8 +426,8 @@ void Terminal::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle)
return;
}
_buffer->GetCursor().SetType(finalCursorType);
_buffer->GetCursor().SetBlinkingAllowed(shouldBlink);
_activeBuffer().GetCursor().SetType(finalCursorType);
_activeBuffer().GetCursor().SetBlinkingAllowed(shouldBlink);
}
void Terminal::SetInputMode(const TerminalInput::Mode mode, const bool enabled)
@@ -426,7 +440,7 @@ void Terminal::SetRenderMode(const RenderSettings::Mode mode, const bool enabled
_renderSettings.SetRenderMode(mode, enabled);
// Repaint everything - the colors will have changed
_buffer->TriggerRedrawAll();
_activeBuffer().TriggerRedrawAll();
}
void Terminal::EnableXtermBracketedPasteMode(const bool enabled)
@@ -447,12 +461,12 @@ bool Terminal::IsVtInputEnabled() const
void Terminal::SetCursorVisibility(const bool visible)
{
_buffer->GetCursor().SetIsVisible(visible);
_activeBuffer().GetCursor().SetIsVisible(visible);
}
void Terminal::EnableCursorBlinking(const bool enable)
{
_buffer->GetCursor().SetBlinkingAllowed(enable);
_activeBuffer().GetCursor().SetBlinkingAllowed(enable);
// GH#2642 - From what we've gathered from other terminals, when blinking is
// disabled, the cursor should remain On always, and have the visibility
@@ -460,7 +474,7 @@ void Terminal::EnableCursorBlinking(const bool enable)
// to disable blinking, the cursor stays stuck On. At this point, only the
// cursor visibility property controls whether the user can see it or not.
// (Yes, the cursor can be On and NOT Visible)
_buffer->GetCursor().SetIsOn(true);
_activeBuffer().GetCursor().SetIsOn(true);
}
void Terminal::CopyToClipboard(std::wstring_view content)
@@ -477,11 +491,11 @@ void Terminal::CopyToClipboard(std::wstring_view content)
// - <none>
void Terminal::AddHyperlink(std::wstring_view uri, std::wstring_view params)
{
auto attr = _buffer->GetCurrentAttributes();
const auto id = _buffer->GetHyperlinkId(uri, params);
auto attr = _activeBuffer().GetCurrentAttributes();
const auto id = _activeBuffer().GetHyperlinkId(uri, params);
attr.SetHyperlinkId(id);
_buffer->SetCurrentAttributes(attr);
_buffer->AddHyperlinkToMap(uri, id);
_activeBuffer().SetCurrentAttributes(attr);
_activeBuffer().AddHyperlinkToMap(uri, id);
}
// Method Description:
@@ -490,9 +504,9 @@ void Terminal::AddHyperlink(std::wstring_view uri, std::wstring_view params)
// - <none>
void Terminal::EndHyperlink()
{
auto attr = _buffer->GetCurrentAttributes();
auto attr = _activeBuffer().GetCurrentAttributes();
attr.SetHyperlinkId(0);
_buffer->SetCurrentAttributes(attr);
_activeBuffer().SetCurrentAttributes(attr);
}
// Method Description:
@@ -565,7 +579,7 @@ std::wstring_view Terminal::GetWorkingDirectory()
// - <none>
void Terminal::PushGraphicsRendition(const VTParameters options)
{
_sgrStack.Push(_buffer->GetCurrentAttributes(), options);
_sgrStack.Push(_activeBuffer().GetCurrentAttributes(), options);
}
// Method Description:
@@ -577,6 +591,149 @@ void Terminal::PushGraphicsRendition(const VTParameters options)
// - <none>
void Terminal::PopGraphicsRendition()
{
const TextAttribute current = _buffer->GetCurrentAttributes();
_buffer->SetCurrentAttributes(_sgrStack.Pop(current));
const TextAttribute current = _activeBuffer().GetCurrentAttributes();
_activeBuffer().SetCurrentAttributes(_sgrStack.Pop(current));
}
void Terminal::UseAlternateScreenBuffer()
{
// the new alt buffer is exactly the size of the viewport.
_altBufferSize = til::size{ _mutableViewport.Dimensions() };
const auto cursorSize = _mainBuffer->GetCursor().GetSize();
// Create a new alt buffer
_altBuffer = std::make_unique<TextBuffer>(_altBufferSize.to_win32_coord(),
TextAttribute{},
cursorSize,
true,
_mainBuffer->GetRenderer());
_mainBuffer->SetAsActiveBuffer(false);
// Copy our cursor state to the new buffer's cursor
{
// Update the alt buffer's cursor style, visibility, and position to match our own.
auto& myCursor = _mainBuffer->GetCursor();
auto& tgtCursor = _altBuffer->GetCursor();
tgtCursor.SetStyle(myCursor.GetSize(), myCursor.GetType());
tgtCursor.SetIsVisible(myCursor.IsVisible());
tgtCursor.SetBlinkingAllowed(myCursor.IsBlinkingAllowed());
// The new position should match the viewport-relative position of the main buffer.
auto tgtCursorPos = myCursor.GetPosition();
tgtCursorPos.Y -= _mutableViewport.Top();
tgtCursor.SetPosition(tgtCursorPos);
}
// update all the hyperlinks on the screen
UpdatePatternsUnderLock();
// GH#3321: Make sure we let the TerminalInput know that we switched
// buffers. This might affect how we interpret certain mouse events.
_terminalInput->UseAlternateScreenBuffer();
// Update scrollbars
_NotifyScrollEvent();
// redraw the screen
try
{
_activeBuffer().TriggerRedrawAll();
}
CATCH_LOG();
}
void Terminal::UseMainScreenBuffer()
{
// Short-circuit: do nothing.
if (!_inAltBuffer())
{
return;
}
// Copy our cursor state back to the main buffer's cursor
{
// Update the alt buffer's cursor style, visibility, and position to match our own.
auto& myCursor = _altBuffer->GetCursor();
auto& tgtCursor = _mainBuffer->GetCursor();
tgtCursor.SetStyle(myCursor.GetSize(), myCursor.GetType());
tgtCursor.SetIsVisible(myCursor.IsVisible());
tgtCursor.SetBlinkingAllowed(myCursor.IsBlinkingAllowed());
// The new position should match the viewport-relative position of the main buffer.
// This is the equal and opposite effect of what we did in UseAlternateScreenBuffer
auto tgtCursorPos = myCursor.GetPosition();
tgtCursorPos.Y += _mutableViewport.Top();
tgtCursor.SetPosition(tgtCursorPos);
}
_mainBuffer->SetAsActiveBuffer(true);
// destroy the alt buffer
_altBuffer = nullptr;
if (_deferredResize.has_value())
{
LOG_IF_FAILED(UserResize(_deferredResize.value().to_win32_coord()));
_deferredResize = std::nullopt;
}
// update all the hyperlinks on the screen
UpdatePatternsUnderLock();
// GH#3321: Make sure we let the TerminalInput know that we switched
// buffers. This might affect how we interpret certain mouse events.
_terminalInput->UseMainScreenBuffer();
// Update scrollbars
_NotifyScrollEvent();
// redraw the screen
try
{
_activeBuffer().TriggerRedrawAll();
}
CATCH_LOG();
}
void Terminal::ClearMenu()
{
_menu.clear();
if (_pfnMenuChanged)
{
_pfnMenuChanged();
}
}
void Terminal::AddToMenu(const Microsoft::Console::VirtualTerminal::DispatchTypes::MenuEntry& entry)
{
// entry;
// for (const auto& entry : menu)
// {
auto n = entry._name;
n;
auto a = 9;
a++;
a;
_menu.push_back(entry);
if (_pfnMenuChanged)
{
_pfnMenuChanged();
}
// }
}
// void Terminal::InvokeMenu(const std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::MenuEntry>& menu)
// {
// menu;
// for (const auto& entry : menu)
// {
// auto n = entry._name;
// n;
// auto a = 9;
// a++;
// a;
// }
// // DebugBreak();
// }

View File

@@ -597,6 +597,128 @@ bool TerminalDispatch::DoConEmuAction(const std::wstring_view string)
return false;
}
// Method Description:
// - Performs a Windows Terminal action
// Arguments:
// - string: contains the parameters that define which action we do
// Return Value:
// - true
bool TerminalDispatch::DoWindowsTerminalAction(const std::wstring_view string)
{
// unsigned int state = 0;
// unsigned int progress = 0;
const auto parts = Utils::SplitString(string, L';');
unsigned int subParam = 0;
if (parts.size() < 1 || !Utils::StringToUint(til::at(parts, 0), subParam))
{
return false;
}
static auto at_or_empty = [](const std::vector<std::wstring_view>& parts, const size_t i) -> std::wstring_view {
if (parts.size() > i)
return til::at(parts, i);
else
return std::wstring_view{};
};
// TODO! 1 is menucomplete
// sequence format is
//
// OSC 9001 ; 1 ; [name GS comment GS input GS ... US ]* ST
//
// So `string` is "1;[name GS comment GS input GS ... US]*"
// * `string[2:]` is the list of records.
// * Split those by US, then iterate and construct entries
// * split by GS and take whatever we have.
if (subParam == 0)
{
_terminalApi.ClearMenu();
}
if (subParam == 1)
{
// if (parts.size() >= 2)
// {
// // A state parameter is defined, parse it out
// const auto stateSuccess = Utils::StringToUint(til::at(parts, 1), state);
// if (!stateSuccess && !til::at(parts, 1).empty())
// {
// return false;
// }
// if (parts.size() >= 3)
// {
// // A progress parameter is also defined, parse it out
// const auto progressSuccess = Utils::StringToUint(til::at(parts, 2), progress);
// if (!progressSuccess && !til::at(parts, 2).empty())
// {
// return false;
// }
// }
// }
// if (state > TaskbarMaxState)
// {
// // state is out of bounds, return false
// return false;
// }
// if (progress > TaskbarMaxProgress)
// {
// // progress is greater than the maximum allowed value, clamp it to the max
// progress = TaskbarMaxProgress;
// }
// _terminalApi.SetTaskbarProgress(static_cast<DispatchTypes::TaskbarState>(state), progress);
// return true;
if (parts.size() <= 1)
{
// // Shortcut: OSC 9001 ; 1 ST
// // clear the entries.
// const std::vector<DispatchTypes::MenuEntry> menu;
// _terminalApi.AppendToMenu(menu);
}
else
{
// std::vector<DispatchTypes::MenuEntry> menu;
const std::wstring_view entryString{ string.substr(2) };
// const auto entries = Utils::SplitString(string, L'\x7F'); // US - unit separator
// for (const auto& entryString : entries)
// {
const auto params{ Utils::SplitString(entryString, L'\x7F') }; // DEL
DispatchTypes::MenuEntry entry{ at_or_empty(params, 0), at_or_empty(params, 1), at_or_empty(params, 2) };
// menu.push_back(std::move(entry));
// }
_terminalApi.AddToMenu(entry);
}
}
// // 9 is SetWorkingDirectory, which informs the terminal about the current working directory.
// else if (subParam == 9)
// {
// if (parts.size() >= 2)
// {
// const auto path = til::at(parts, 1);
// // The path should be surrounded with '"' according to the documentation of ConEmu.
// // An example: 9;"D:/"
// if (path.at(0) == L'"' && path.at(path.size() - 1) == L'"' && path.size() >= 3)
// {
// _terminalApi.SetWorkingDirectory(path.substr(1, path.size() - 2));
// }
// else
// {
// // If we fail to find the surrounding quotation marks, we'll give the path a try anyway.
// // ConEmu also does this.
// _terminalApi.SetWorkingDirectory(path);
// }
// return true;
// }
// }
return false;
}
// Routine Description:
// - Helper to send a string reply to the input stream of the console.
// - Used by various commands where the program attached would like a reply to one of the commands issued.
@@ -658,6 +780,9 @@ bool TerminalDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param,
case DispatchTypes::ModeParams::W32IM_Win32InputMode:
success = EnableWin32InputMode(enable);
break;
case DispatchTypes::ModeParams::ASB_AlternateScreenBuffer:
success = enable ? UseAlternateScreenBuffer() : UseMainScreenBuffer();
break;
default:
// If no functions to call, overall dispatch was a failure.
success = false;
@@ -786,3 +911,84 @@ bool TerminalDispatch::HardReset()
return true;
}
// Routine Description:
// - DECSC - Saves the current "cursor state" into a memory buffer. This
// includes the cursor position, origin mode, graphic rendition, and
// active character set.
// Arguments:
// - <none>
// Return Value:
// - True.
bool TerminalDispatch::CursorSaveState()
{
// TODO GH#3849: When de-duplicating this, the AdaptDispatch version of this
// is more elaborate.
const auto attributes = _terminalApi.GetTextAttributes();
COORD coordCursor = _terminalApi.GetCursorPosition();
// The cursor is given to us by the API as relative to current viewport top.
// VT is also 1 based, not 0 based, so correct by 1.
auto& savedCursorState = _savedCursorState.at(_usingAltBuffer);
savedCursorState.Column = coordCursor.X + 1;
savedCursorState.Row = coordCursor.Y + 1;
savedCursorState.Attributes = attributes;
return true;
}
// Routine Description:
// - DECRC - Restores a saved "cursor state" from the DECSC command back into
// the console state. This includes the cursor position, origin mode, graphic
// rendition, and active character set.
// Arguments:
// - <none>
// Return Value:
// - True.
bool TerminalDispatch::CursorRestoreState()
{
// TODO GH#3849: When de-duplicating this, the AdaptDispatch version of this
// is more elaborate.
auto& savedCursorState = _savedCursorState.at(_usingAltBuffer);
auto row = savedCursorState.Row;
const auto col = savedCursorState.Column;
// The saved coordinates are always absolute, so we need reset the origin mode temporarily.
CursorPosition(row, col);
// Restore text attributes.
_terminalApi.SetTextAttributes(savedCursorState.Attributes);
return true;
}
// - ASBSET - Creates and swaps to the alternate screen buffer. In virtual terminals, there exists both a "main"
// screen buffer and an alternate. ASBSET creates a new alternate, and switches to it. If there is an already
// existing alternate, it is discarded.
// Arguments:
// - None
// Return Value:
// - True.
bool TerminalDispatch::UseAlternateScreenBuffer()
{
CursorSaveState();
_terminalApi.UseAlternateScreenBuffer();
_usingAltBuffer = true;
return true;
}
// Routine Description:
// - ASBRST - From the alternate buffer, returns to the main screen buffer.
// From the main screen buffer, does nothing. The alternate is discarded.
// Arguments:
// - None
// Return Value:
// - True.
bool TerminalDispatch::UseMainScreenBuffer()
{
_terminalApi.UseMainScreenBuffer();
_usingAltBuffer = false;
CursorRestoreState();
return true;
}

View File

@@ -39,6 +39,9 @@ public:
bool CarriageReturn() override;
bool SetWindowTitle(std::wstring_view title) override;
bool UseAlternateScreenBuffer() override; // ASBSET
bool UseMainScreenBuffer() override; // ASBRST
bool HorizontalTabSet() override; // HTS
bool ForwardTab(const size_t numTabs) override; // CHT, HT
bool BackwardsTab(const size_t numTabs) override; // CBT
@@ -81,13 +84,33 @@ public:
bool EndHyperlink() override;
bool DoConEmuAction(const std::wstring_view string) override;
bool DoWindowsTerminalAction(const std::wstring_view string) override;
bool CursorSaveState() override;
bool CursorRestoreState() override;
private:
::Microsoft::Terminal::Core::ITerminalApi& _terminalApi;
// Dramatically simplified version of AdaptDispatch::CursorState
struct CursorState
{
unsigned int Row = 1;
unsigned int Column = 1;
TextAttribute Attributes = {};
};
std::vector<bool> _tabStopColumns;
bool _initDefaultTabStops = true;
// We have two instances of the saved cursor state, because we need
// one for the main buffer (at index 0), and another for the alt buffer
// (at index 1). The _usingAltBuffer property keeps tracks of which
// buffer is active, so can be used as an index into this array to
// obtain the saved state that should be currently active.
std::array<CursorState, 2> _savedCursorState;
bool _usingAltBuffer = false;
size_t _SetRgbColorsHelper(const ::Microsoft::Console::VirtualTerminal::VTParameters options,
TextAttribute& attr,
const bool isForeground);

View File

@@ -54,7 +54,7 @@ std::vector<SMALL_RECT> Terminal::_GetSelectionRects() const noexcept
try
{
return _buffer->GetTextRects(_selection->start, _selection->end, _blockSelection, false);
return _activeBuffer().GetTextRects(_selection->start, _selection->end, _blockSelection, false);
}
CATCH_LOG();
return result;
@@ -182,7 +182,7 @@ void Terminal::SetSelectionEnd(const COORD viewportPos, std::optional<SelectionE
// - the new start/end for a selection
std::pair<COORD, COORD> Terminal::_PivotSelection(const COORD targetPos, bool& targetStart) const
{
if (targetStart = _buffer->GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0)
if (targetStart = _activeBuffer().GetSize().CompareInBounds(targetPos, _selection->pivot) <= 0)
{
// target is before pivot
// treat target as start
@@ -207,7 +207,7 @@ std::pair<COORD, COORD> Terminal::_ExpandSelectionAnchors(std::pair<COORD, COORD
COORD start = anchors.first;
COORD end = anchors.second;
const auto bufferSize = _buffer->GetSize();
const auto bufferSize = _activeBuffer().GetSize();
switch (_multiClickSelectionMode)
{
case SelectionExpansion::Line:
@@ -215,8 +215,8 @@ std::pair<COORD, COORD> Terminal::_ExpandSelectionAnchors(std::pair<COORD, COORD
end = { bufferSize.RightInclusive(), end.Y };
break;
case SelectionExpansion::Word:
start = _buffer->GetWordStart(start, _wordDelimiters);
end = _buffer->GetWordEnd(end, _wordDelimiters);
start = _activeBuffer().GetWordStart(start, _wordDelimiters);
end = _activeBuffer().GetWordEnd(end, _wordDelimiters);
break;
case SelectionExpansion::Char:
default:
@@ -325,7 +325,7 @@ void Terminal::UpdateSelection(SelectionDirection direction, SelectionExpansion
_scrollOffset -= amtBelowView;
}
_NotifyScrollEvent();
_buffer->TriggerScroll();
_activeBuffer().TriggerScroll();
}
}
@@ -334,22 +334,22 @@ void Terminal::_MoveByChar(SelectionDirection direction, COORD& pos)
switch (direction)
{
case SelectionDirection::Left:
_buffer->GetSize().DecrementInBounds(pos);
pos = _buffer->GetGlyphStart(til::point{ pos }).to_win32_coord();
_activeBuffer().GetSize().DecrementInBounds(pos);
pos = _activeBuffer().GetGlyphStart(til::point{ pos }).to_win32_coord();
break;
case SelectionDirection::Right:
_buffer->GetSize().IncrementInBounds(pos);
pos = _buffer->GetGlyphEnd(til::point{ pos }).to_win32_coord();
_activeBuffer().GetSize().IncrementInBounds(pos);
pos = _activeBuffer().GetGlyphEnd(til::point{ pos }).to_win32_coord();
break;
case SelectionDirection::Up:
{
const auto bufferSize{ _buffer->GetSize() };
const auto bufferSize{ _activeBuffer().GetSize() };
pos = { pos.X, std::clamp(base::ClampSub<short, short>(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) };
break;
}
case SelectionDirection::Down:
{
const auto bufferSize{ _buffer->GetSize() };
const auto bufferSize{ _activeBuffer().GetSize() };
pos = { pos.X, std::clamp(base::ClampAdd<short, short>(pos.Y, 1).RawValue(), bufferSize.Top(), bufferSize.BottomInclusive()) };
break;
}
@@ -361,19 +361,19 @@ void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos)
switch (direction)
{
case SelectionDirection::Left:
const auto wordStartPos{ _buffer->GetWordStart(pos, _wordDelimiters) };
if (_buffer->GetSize().CompareInBounds(_selection->pivot, pos) < 0)
const auto wordStartPos{ _activeBuffer().GetWordStart(pos, _wordDelimiters) };
if (_activeBuffer().GetSize().CompareInBounds(_selection->pivot, pos) < 0)
{
// If we're moving towards the pivot, move one more cell
pos = wordStartPos;
_buffer->GetSize().DecrementInBounds(pos);
_activeBuffer().GetSize().DecrementInBounds(pos);
}
else if (wordStartPos == pos)
{
// already at the beginning of the current word,
// move to the beginning of the previous word
_buffer->GetSize().DecrementInBounds(pos);
pos = _buffer->GetWordStart(pos, _wordDelimiters);
_activeBuffer().GetSize().DecrementInBounds(pos);
pos = _activeBuffer().GetWordStart(pos, _wordDelimiters);
}
else
{
@@ -382,19 +382,19 @@ void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos)
}
break;
case SelectionDirection::Right:
const auto wordEndPos{ _buffer->GetWordEnd(pos, _wordDelimiters) };
if (_buffer->GetSize().CompareInBounds(pos, _selection->pivot) < 0)
const auto wordEndPos{ _activeBuffer().GetWordEnd(pos, _wordDelimiters) };
if (_activeBuffer().GetSize().CompareInBounds(pos, _selection->pivot) < 0)
{
// If we're moving towards the pivot, move one more cell
pos = _buffer->GetWordEnd(pos, _wordDelimiters);
_buffer->GetSize().IncrementInBounds(pos);
pos = _activeBuffer().GetWordEnd(pos, _wordDelimiters);
_activeBuffer().GetSize().IncrementInBounds(pos);
}
else if (wordEndPos == pos)
{
// already at the end of the current word,
// move to the end of the next word
_buffer->GetSize().IncrementInBounds(pos);
pos = _buffer->GetWordEnd(pos, _wordDelimiters);
_activeBuffer().GetSize().IncrementInBounds(pos);
pos = _activeBuffer().GetWordEnd(pos, _wordDelimiters);
}
else
{
@@ -404,18 +404,18 @@ void Terminal::_MoveByWord(SelectionDirection direction, COORD& pos)
break;
case SelectionDirection::Up:
_MoveByChar(direction, pos);
pos = _buffer->GetWordStart(pos, _wordDelimiters);
pos = _activeBuffer().GetWordStart(pos, _wordDelimiters);
break;
case SelectionDirection::Down:
_MoveByChar(direction, pos);
pos = _buffer->GetWordEnd(pos, _wordDelimiters);
pos = _activeBuffer().GetWordEnd(pos, _wordDelimiters);
break;
}
}
void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos)
{
const auto bufferSize{ _buffer->GetSize() };
const auto bufferSize{ _activeBuffer().GetSize() };
switch (direction)
{
case SelectionDirection::Left:
@@ -426,15 +426,15 @@ void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos)
break;
case SelectionDirection::Up:
{
const auto viewportHeight{ _mutableViewport.Height() };
const auto viewportHeight{ _GetMutableViewport().Height() };
const auto newY{ base::ClampSub<short, short>(pos.Y, viewportHeight) };
pos = newY < bufferSize.Top() ? bufferSize.Origin() : COORD{ pos.X, newY };
break;
}
case SelectionDirection::Down:
{
const auto viewportHeight{ _mutableViewport.Height() };
const auto mutableBottom{ _mutableViewport.BottomInclusive() };
const auto viewportHeight{ _GetMutableViewport().Height() };
const auto mutableBottom{ _GetMutableViewport().BottomInclusive() };
const auto newY{ base::ClampAdd<short, short>(pos.Y, viewportHeight) };
pos = newY > mutableBottom ? COORD{ bufferSize.RightInclusive(), mutableBottom } : COORD{ pos.X, newY };
break;
@@ -444,7 +444,7 @@ void Terminal::_MoveByViewport(SelectionDirection direction, COORD& pos)
void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos)
{
const auto bufferSize{ _buffer->GetSize() };
const auto bufferSize{ _activeBuffer().GetSize() };
switch (direction)
{
case SelectionDirection::Left:
@@ -453,7 +453,7 @@ void Terminal::_MoveByBuffer(SelectionDirection direction, COORD& pos)
break;
case SelectionDirection::Right:
case SelectionDirection::Down:
pos = { bufferSize.RightInclusive(), _mutableViewport.BottomInclusive() };
pos = { bufferSize.RightInclusive(), _GetMutableViewport().BottomInclusive() };
break;
}
}
@@ -489,7 +489,7 @@ const TextBuffer::TextAndColor Terminal::RetrieveSelectedTextFromBuffer(bool sin
const auto includeCRLF = !singleLine || _blockSelection;
const auto trimTrailingWhitespace = !singleLine && (!_blockSelection || _trimBlockSelection);
const auto formatWrappedRows = _blockSelection;
return _buffer->GetText(includeCRLF, trimTrailingWhitespace, selectionRects, GetAttributeColors, formatWrappedRows);
return _activeBuffer().GetText(includeCRLF, trimTrailingWhitespace, selectionRects, GetAttributeColors, formatWrappedRows);
}
// Method Description:
@@ -502,7 +502,7 @@ COORD Terminal::_ConvertToBufferCell(const COORD viewportPos) const
{
const auto yPos = base::ClampedNumeric<short>(_VisibleStartIndex()) + viewportPos.Y;
COORD bufferPos = { viewportPos.X, yPos };
_buffer->GetSize().Clamp(bufferPos);
_activeBuffer().GetSize().Clamp(bufferPos);
return bufferPos;
}

View File

@@ -25,7 +25,7 @@ COORD Terminal::GetTextBufferEndPosition() const noexcept
const TextBuffer& Terminal::GetTextBuffer() noexcept
{
return *_buffer;
return _activeBuffer();
}
const FontInfo& Terminal::GetFontInfo() noexcept
@@ -40,19 +40,19 @@ void Terminal::SetFontInfo(const FontInfo& fontInfo)
COORD Terminal::GetCursorPosition() const noexcept
{
const auto& cursor = _buffer->GetCursor();
const auto& cursor = _activeBuffer().GetCursor();
return cursor.GetPosition();
}
bool Terminal::IsCursorVisible() const noexcept
{
const auto& cursor = _buffer->GetCursor();
const auto& cursor = _activeBuffer().GetCursor();
return cursor.IsVisible() && !cursor.IsPopupShown();
}
bool Terminal::IsCursorOn() const noexcept
{
const auto& cursor = _buffer->GetCursor();
const auto& cursor = _activeBuffer().GetCursor();
return cursor.IsOn();
}
@@ -63,18 +63,18 @@ ULONG Terminal::GetCursorPixelWidth() const noexcept
ULONG Terminal::GetCursorHeight() const noexcept
{
return _buffer->GetCursor().GetSize();
return _activeBuffer().GetCursor().GetSize();
}
CursorType Terminal::GetCursorStyle() const noexcept
{
return _buffer->GetCursor().GetType();
return _activeBuffer().GetCursor().GetType();
}
bool Terminal::IsCursorDoubleWidth() const
{
const auto position = _buffer->GetCursor().GetPosition();
TextBufferTextIterator it(TextBufferCellIterator(*_buffer, position));
const auto position = _activeBuffer().GetCursor().GetPosition();
TextBufferTextIterator it(TextBufferCellIterator(_activeBuffer(), position));
return IsGlyphFullWidth(*it);
}
@@ -90,12 +90,12 @@ const bool Terminal::IsGridLineDrawingAllowed() noexcept
const std::wstring Microsoft::Terminal::Core::Terminal::GetHyperlinkUri(uint16_t id) const noexcept
{
return _buffer->GetHyperlinkUriFromId(id);
return _activeBuffer().GetHyperlinkUriFromId(id);
}
const std::wstring Microsoft::Terminal::Core::Terminal::GetHyperlinkCustomId(uint16_t id) const noexcept
{
return _buffer->GetCustomIdFromId(id);
return _activeBuffer().GetCustomIdFromId(id);
}
// Method Description:
@@ -174,7 +174,7 @@ void Terminal::SelectNewRegion(const COORD coordStart, const COORD coordEnd)
if (notifyScrollChange)
{
_buffer->TriggerScroll();
_activeBuffer().TriggerScroll();
_NotifyScrollEvent();
}
@@ -227,5 +227,5 @@ const bool Terminal::IsUiaDataInitialized() const noexcept
// when a screen reader requests it. However, the terminal might not be fully
// initialized yet. So we use this to check if any crucial components of
// UiaData are not yet initialized.
return !!_buffer;
return !!_mainBuffer;
}

View File

@@ -713,6 +713,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
BASIC_FACTORY(RenameTabArgs);
BASIC_FACTORY(SwapPaneArgs);
BASIC_FACTORY(SplitPaneArgs);
BASIC_FACTORY(SendInputArgs);
BASIC_FACTORY(SetFocusModeArgs);
BASIC_FACTORY(SetFullScreenArgs);
BASIC_FACTORY(SetMaximizedArgs);

View File

@@ -192,6 +192,7 @@ namespace Microsoft.Terminal.Settings.Model
[default_interface] runtimeclass SendInputArgs : IActionArgs
{
SendInputArgs(String input);
String Input { get; };
};

View File

@@ -32,8 +32,8 @@ namespace Microsoft.Terminal.Settings.Model
{
Command();
String Name { get; };
ActionAndArgs ActionAndArgs { get; };
String Name;
ActionAndArgs ActionAndArgs;
Microsoft.Terminal.Control.KeyChord Keys { get; };
void RegisterKey(Microsoft.Terminal.Control.KeyChord keys);
String KeyChordText { get; };

View File

@@ -222,6 +222,9 @@ class TerminalCoreUnitTests::ConptyRoundtripTests final
TEST_METHOD(ClearBufferSignal);
TEST_METHOD(SimpleAltBufferTest);
TEST_METHOD(AltBufferToAltBufferTest);
private:
bool _writeCallback(const char* const pch, size_t const cch);
void _flushFirstFrame();
@@ -322,7 +325,7 @@ void ConptyRoundtripTests::_clearConpty()
// After we resize, make sure to get the new textBuffers
return { &ServiceLocator::LocateGlobals().getConsoleInformation().GetActiveOutputBuffer().GetTextBuffer(),
term->_buffer.get() };
term->_mainBuffer.get() };
}
void ConptyRoundtripTests::ConptyOutputTestCanary()
@@ -344,7 +347,7 @@ void ConptyRoundtripTests::SimpleWriteOutputTest()
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -367,7 +370,7 @@ void ConptyRoundtripTests::WriteTwoLinesUsesNewline()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -402,7 +405,7 @@ void ConptyRoundtripTests::WriteAFewSimpleLines()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -443,7 +446,7 @@ void ConptyRoundtripTests::TestWrappingALongString()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
_checkConptyOutput = false;
@@ -494,7 +497,7 @@ void ConptyRoundtripTests::TestAdvancedWrapping()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
const auto initialTermView = term->GetViewport();
_flushFirstFrame();
@@ -559,7 +562,7 @@ void ConptyRoundtripTests::TestExactWrappingWithoutSpaces()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
const auto initialTermView = term->GetViewport();
@@ -621,7 +624,7 @@ void ConptyRoundtripTests::TestExactWrappingWithSpaces()
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
const auto initialTermView = term->GetViewport();
_flushFirstFrame();
@@ -683,7 +686,7 @@ void ConptyRoundtripTests::MoveCursorAtEOL()
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
Log::Comment(NoThrowString().Format(
@@ -762,7 +765,7 @@ void ConptyRoundtripTests::TestResizeHeight()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
const auto initialHostView = si.GetViewport();
const auto initialTermView = term->GetViewport();
const auto initialTerminalBufferHeight = term->GetTextBuffer().GetSize().Height();
@@ -962,7 +965,7 @@ void ConptyRoundtripTests::PassthroughCursorShapeImmediately()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -989,7 +992,7 @@ void ConptyRoundtripTests::PassthroughClearScrollback()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -1066,7 +1069,7 @@ void ConptyRoundtripTests::PassthroughClearAll()
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
auto& sm = si.GetStateMachine();
@@ -1153,7 +1156,7 @@ void ConptyRoundtripTests::PassthroughHardReset()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -1217,7 +1220,7 @@ void ConptyRoundtripTests::OutputWrappedLinesAtTopOfBuffer()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -1265,7 +1268,7 @@ void ConptyRoundtripTests::OutputWrappedLinesAtBottomOfBuffer()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -1398,7 +1401,7 @@ void ConptyRoundtripTests::ScrollWithChangesInMiddle()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -1499,7 +1502,7 @@ void ConptyRoundtripTests::ScrollWithMargins()
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
const auto initialTermView = term->GetViewport();
Log::Comment(L"Flush first frame.");
@@ -1743,7 +1746,7 @@ void ConptyRoundtripTests::DontWrapMoveCursorInSingleFrame()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -1836,7 +1839,7 @@ void ConptyRoundtripTests::ClearHostTrickeryTest()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -1944,7 +1947,7 @@ void ConptyRoundtripTests::OverstrikeAtBottomOfBuffer()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -2022,7 +2025,7 @@ void ConptyRoundtripTests::MarginsWithStatusLine()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -2113,7 +2116,7 @@ void ConptyRoundtripTests::OutputWrappedLineWithSpace()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -2179,7 +2182,7 @@ void ConptyRoundtripTests::OutputWrappedLineWithSpaceAtBottomOfBuffer()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -2334,8 +2337,6 @@ void ConptyRoundtripTests::BreakLinesOnCursorMovement()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& termTb = *term->_buffer;
_flushFirstFrame();
// Any of the cursor movements that use a LF will actually hard break the
@@ -2475,8 +2476,9 @@ void ConptyRoundtripTests::BreakLinesOnCursorMovement()
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state ==========");
verifyBuffer(termTb, til::rect{ term->_mutableViewport.ToInclusive() });
// GH#3492: Now that we support the alt buffer, make sure to validate the
// _alt buffer's_ contents.
verifyBuffer(*term->_altBuffer, til::rect{ term->_mutableViewport.ToInclusive() });
}
void ConptyRoundtripTests::TestCursorInDeferredEOLPositionOnNewLineWithSpaces()
@@ -2488,7 +2490,7 @@ void ConptyRoundtripTests::TestCursorInDeferredEOLPositionOnNewLineWithSpaces()
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
const auto termView = term->GetViewport();
_flushFirstFrame();
@@ -2549,7 +2551,7 @@ void ConptyRoundtripTests::ResizeRepaintVimExeBuffer()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
_flushFirstFrame();
@@ -2678,7 +2680,7 @@ void ConptyRoundtripTests::ClsAndClearHostClearsScrollbackTest()
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
auto& sm = si.GetStateMachine();
@@ -2833,7 +2835,7 @@ void ConptyRoundtripTests::TestResizeWithCookedRead()
auto& gci = g.getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
_flushFirstFrame();
@@ -2894,7 +2896,7 @@ void ConptyRoundtripTests::ResizeInitializeBufferWithDefaultAttrs()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
_flushFirstFrame();
@@ -3021,7 +3023,7 @@ void ConptyRoundtripTests::NewLinesAtBottomWithBackground()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
_flushFirstFrame();
@@ -3191,7 +3193,7 @@ void ConptyRoundtripTests::WrapNewLineAtBottom()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
_flushFirstFrame();
@@ -3349,7 +3351,7 @@ void ConptyRoundtripTests::WrapNewLineAtBottomLikeMSYS()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
_flushFirstFrame();
@@ -3533,7 +3535,7 @@ void ConptyRoundtripTests::DeleteWrappedWord()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
_flushFirstFrame();
@@ -3625,7 +3627,7 @@ void ConptyRoundtripTests::HyperlinkIdConsistency()
auto& si = gci.GetActiveOutputBuffer();
auto& hostSm = si.GetStateMachine();
auto& hostTb = si.GetTextBuffer();
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
_flushFirstFrame();
@@ -3690,7 +3692,7 @@ void ConptyRoundtripTests::ClearBufferSignal()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
auto* hostTb = &si.GetTextBuffer();
auto* termTb = term->_buffer.get();
auto* termTb = term->_mainBuffer.get();
_flushFirstFrame();
@@ -3705,12 +3707,11 @@ void ConptyRoundtripTests::ClearBufferSignal()
// B's are in red-on-yellow
sm.ProcessString(L"\x1b[?25l");
sm.ProcessString(L"\x1b[?34;42m");
sm.ProcessString(L"\x1b[34;42m");
sm.ProcessString(std::wstring(50, L'A'));
sm.ProcessString(L" ");
sm.ProcessString(L"\x1b[?31;43m");
sm.ProcessString(L"\x1b[31;43m");
sm.ProcessString(std::wstring(50, L'B'));
sm.ProcessString(L"\x1b[?m");
sm.ProcessString(L"\x1b[?25h");
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const bool before) {
@@ -3752,3 +3753,318 @@ void ConptyRoundtripTests::ClearBufferSignal()
Log::Comment(L"========== Checking the terminal buffer state (after) ==========");
verifyBuffer(*termTb, til::rect{ term->_mutableViewport.ToInclusive() }, false);
}
void ConptyRoundtripTests::SimpleAltBufferTest()
{
Log::Comment(L"A test for entering and exiting the alt buffer, via conpty. "
L"Ensures cursor is in the right place, and contents are "
L"restored accordingly.");
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->_mainBuffer.get();
_flushFirstFrame();
_checkConptyOutput = false;
_logConpty = true;
// Print two lines of text:
// |AAAAAAAA | <break>
// |BBBBBBBB_ | <break>
// (cursor on the '_')
// A's are in blue-on-green,
// B's are in red-on-yellow
// A one line version: (more or less)
//
// printf "\x1b[2J\x1b[H" ; printf
// "\x1b[?25l\x1b[34;42mAAAAA\n\x1b[31;43mBBBBB\x1b[?25h" ; sleep 2 ; printf
// "\x1b[?1049h" ; sleep 2 ; printf "CCCCC" ; sleep 2 ; printf "\x1b[?1049l"
// ; sleep 2
sm.ProcessString(L"\x1b[?25l");
sm.ProcessString(L"\x1b[34;42m");
sm.ProcessString(std::wstring(50, L'A'));
sm.ProcessString(L"\n");
sm.ProcessString(L"\x1b[31;43m");
sm.ProcessString(std::wstring(50, L'B'));
sm.ProcessString(L"\x1b[?25h");
// Four frames here:
// * After text is printed to main buffer
// * after we go to the alt buffer
// * print more to the alt buffer
// * after we go back to the buffer
enum class Frame : int
{
InMainBufferBefore = 0,
InAltBufferBefore,
InAltBufferAfter,
InMainBufferAfter
};
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const Frame frame) {
const short width = viewport.narrow_width<short>();
auto iter0 = tb.GetCellDataAt({ 0, 0 });
auto iter1 = tb.GetCellDataAt({ 0, 1 });
switch (frame)
{
case Frame::InMainBufferBefore:
case Frame::InMainBufferAfter:
{
TestUtils::VerifySpanOfText(L"A", iter0, 0, 50);
TestUtils::VerifySpanOfText(L" ", iter0, 0, static_cast<size_t>(width - 50));
TestUtils::VerifySpanOfText(L"B", iter1, 0, 50);
TestUtils::VerifySpanOfText(L" ", iter1, 0, static_cast<size_t>(width - 50));
COORD expectedCursor{ 50, 1 };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
break;
}
case Frame::InAltBufferBefore:
{
TestUtils::VerifySpanOfText(L" ", iter0, 0, width);
TestUtils::VerifySpanOfText(L" ", iter1, 0, width);
COORD expectedCursor{ 50, 1 };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
break;
}
case Frame::InAltBufferAfter:
{
TestUtils::VerifySpanOfText(L" ", iter0, 0, width);
TestUtils::VerifySpanOfText(L" ", iter1, 0, 50u);
TestUtils::VerifySpanOfText(L"C", iter1, 0, 5u);
TestUtils::VerifySpanOfText(L" ", iter1, 0, static_cast<size_t>(width - 55));
COORD expectedCursor{ 55, 1 };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
break;
}
}
};
Log::Comment(L"========== Checking the host buffer state (InMainBufferBefore) ==========");
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, Frame::InMainBufferBefore);
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state (InMainBufferBefore) ==========");
VERIFY_ARE_EQUAL(0, term->_GetMutableViewport().Top());
verifyBuffer(*termTb, til::rect{ term->_GetMutableViewport().ToInclusive() }, Frame::InMainBufferBefore);
Log::Comment(L"========== Switch to the alt buffer ==========");
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
sm.ProcessString(L"\x1b[?1049h");
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
auto& siAlt = gci.GetActiveOutputBuffer();
auto* hostAltTb = &siAlt.GetTextBuffer();
auto* termAltTb = &term->_activeBuffer();
VERIFY_IS_TRUE(term->_inAltBuffer());
VERIFY_ARE_NOT_EQUAL(termAltTb, termTb);
Log::Comment(L"========== Checking the host buffer state (InAltBufferBefore) ==========");
verifyBuffer(*hostAltTb, til::rect{ siAlt.GetViewport().ToInclusive() }, Frame::InAltBufferBefore);
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state (InAltBufferBefore) ==========");
VERIFY_ARE_EQUAL(0, term->_GetMutableViewport().Top());
verifyBuffer(*termAltTb, til::rect{ term->_GetMutableViewport().ToInclusive() }, Frame::InAltBufferBefore);
Log::Comment(L"========== Add some text to the alt buffer ==========");
sm.ProcessString(L"CCCCC");
Log::Comment(L"========== Checking the host buffer state (InAltBufferAfter) ==========");
verifyBuffer(*hostAltTb, til::rect{ siAlt.GetViewport().ToInclusive() }, Frame::InAltBufferAfter);
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state (InAltBufferAfter) ==========");
VERIFY_ARE_EQUAL(0, term->_GetMutableViewport().Top());
verifyBuffer(*termAltTb, til::rect{ term->_GetMutableViewport().ToInclusive() }, Frame::InAltBufferAfter);
Log::Comment(L"========== Back to the main buffer ==========");
sm.ProcessString(L"\x1b[?1049l");
Log::Comment(L"========== Checking the host buffer state (InMainBufferAfter) ==========");
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, Frame::InMainBufferAfter);
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state (InMainBufferAfter) ==========");
VERIFY_ARE_EQUAL(0, term->_GetMutableViewport().Top());
verifyBuffer(*termTb, til::rect{ term->_GetMutableViewport().ToInclusive() }, Frame::InMainBufferAfter);
}
void ConptyRoundtripTests::AltBufferToAltBufferTest()
{
Log::Comment(L"When we request the alt buffer when we're already in the alt buffer, we should still clear it out and replace it.");
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->_mainBuffer.get();
_flushFirstFrame();
_checkConptyOutput = false;
_logConpty = true;
// Print two lines of text:
// |AAAAAAAA | <break>
// |BBBBBBBB_ | <break>
// (cursor on the '_')
// A's are in blue-on-green,
// B's are in red-on-yellow
// A one line version: (more or less)
//
// printf "\x1b[2J\x1b[H" ; printf
// "\x1b[?25l\x1b[34;42mAAAAA\n\x1b[31;43mBBBBB\x1b[?25h" ; sleep 2 ; printf
// "\x1b[?1049h" ; sleep 2 ; printf "CCCCC" ; sleep 2 ; printf "\x1b[?1049h"
// ; sleep 2
sm.ProcessString(L"\x1b[?25l");
sm.ProcessString(L"\x1b[34;42m");
sm.ProcessString(std::wstring(50, L'A'));
sm.ProcessString(L"\n");
sm.ProcessString(L"\x1b[31;43m");
sm.ProcessString(std::wstring(50, L'B'));
sm.ProcessString(L"\x1b[?25h");
// Four frames here:
// * After text is printed to main buffer
// * after we go to the alt buffer
// * print more to the alt buffer
// * after we go back to the buffer
enum class Frame : int
{
InMainBufferBefore = 0,
InAltBufferBefore,
InAltBufferAfter,
StillInAltBuffer
};
auto verifyBuffer = [&](const TextBuffer& tb, const til::rect& viewport, const Frame frame) {
const short width = viewport.narrow_width<short>();
auto iter0 = tb.GetCellDataAt({ 0, 0 });
auto iter1 = tb.GetCellDataAt({ 0, 1 });
switch (frame)
{
case Frame::InMainBufferBefore:
{
TestUtils::VerifySpanOfText(L"A", iter0, 0, 50);
TestUtils::VerifySpanOfText(L" ", iter0, 0, static_cast<size_t>(width - 50));
TestUtils::VerifySpanOfText(L"B", iter1, 0, 50);
TestUtils::VerifySpanOfText(L" ", iter1, 0, static_cast<size_t>(width - 50));
COORD expectedCursor{ 50, 1 };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
break;
}
case Frame::InAltBufferBefore:
{
TestUtils::VerifySpanOfText(L" ", iter0, 0, width);
TestUtils::VerifySpanOfText(L" ", iter1, 0, width);
COORD expectedCursor{ 50, 1 };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
break;
}
case Frame::InAltBufferAfter:
{
TestUtils::VerifySpanOfText(L" ", iter0, 0, width);
TestUtils::VerifySpanOfText(L" ", iter1, 0, 50u);
TestUtils::VerifySpanOfText(L"C", iter1, 0, 5u);
TestUtils::VerifySpanOfText(L" ", iter1, 0, static_cast<size_t>(width - 55));
COORD expectedCursor{ 55, 1 };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
break;
}
case Frame::StillInAltBuffer:
{
TestUtils::VerifySpanOfText(L" ", iter0, 0, width);
TestUtils::VerifySpanOfText(L" ", iter1, 0, width);
COORD expectedCursor{ 55, 1 };
VERIFY_ARE_EQUAL(expectedCursor, tb.GetCursor().GetPosition());
break;
}
}
};
Log::Comment(L"========== Checking the host buffer state (InMainBufferBefore) ==========");
verifyBuffer(*hostTb, til::rect{ si.GetViewport().ToInclusive() }, Frame::InMainBufferBefore);
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state (InMainBufferBefore) ==========");
verifyBuffer(*termTb, til::rect{ term->_GetMutableViewport().ToInclusive() }, Frame::InMainBufferBefore);
Log::Comment(L"========== Switch to the alt buffer ==========");
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
sm.ProcessString(L"\x1b[?1049h");
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
auto* siAlt = &gci.GetActiveOutputBuffer();
auto* hostAltTb = &siAlt->GetTextBuffer();
auto* termAltTb = &term->_activeBuffer();
VERIFY_IS_TRUE(term->_inAltBuffer());
VERIFY_ARE_NOT_EQUAL(termAltTb, termTb);
Log::Comment(L"========== Checking the host buffer state (InAltBufferBefore) ==========");
verifyBuffer(*hostAltTb, til::rect{ siAlt->GetViewport().ToInclusive() }, Frame::InAltBufferBefore);
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state (InAltBufferBefore) ==========");
verifyBuffer(*termAltTb, til::rect{ term->_GetMutableViewport().ToInclusive() }, Frame::InAltBufferBefore);
Log::Comment(L"========== Add some text to the alt buffer ==========");
sm.ProcessString(L"CCCCC");
Log::Comment(L"========== Checking the host buffer state (InAltBufferAfter) ==========");
verifyBuffer(*hostAltTb, til::rect{ siAlt->GetViewport().ToInclusive() }, Frame::InAltBufferAfter);
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
Log::Comment(L"========== Checking the terminal buffer state (InAltBufferAfter) ==========");
verifyBuffer(*termAltTb, til::rect{ term->_GetMutableViewport().ToInclusive() }, Frame::InAltBufferAfter);
Log::Comment(L"========== Stay in the alt buffer, what happens? ==========");
sm.ProcessString(L"\x1b[?1049h");
Log::Comment(L"Painting the frame");
VERIFY_SUCCEEDED(renderer.PaintFrame());
siAlt = &gci.GetActiveOutputBuffer();
hostAltTb = &siAlt->GetTextBuffer();
termAltTb = &term->_activeBuffer();
Log::Comment(L"========== Checking the host buffer state (StillInAltBuffer) ==========");
verifyBuffer(*hostAltTb, til::rect{ siAlt->GetViewport().ToInclusive() }, Frame::StillInAltBuffer);
Log::Comment(L"========== Checking the terminal buffer state (StillInAltBuffer) ==========");
verifyBuffer(*termAltTb, til::rect{ term->_GetMutableViewport().ToInclusive() }, Frame::StillInAltBuffer);
}

View File

@@ -157,7 +157,7 @@ void ScrollTest::TestNotifyScrolling()
Log::Comment(L"Watch out - this test takes a while to run, and won't "
L"output anything unless in encounters an error. This is expected.");
auto& termTb = *_term->_buffer;
auto& termTb = *_term->_mainBuffer;
auto& termSm = *_term->_stateMachine;
const auto totalBufferSize = termTb.GetSize().Height();

View File

@@ -138,29 +138,29 @@ void TerminalApiTest::CursorVisibility()
DummyRenderer renderer{ &term };
term.Create({ 100, 100 }, 0, renderer);
VERIFY_IS_TRUE(term._buffer->GetCursor().IsVisible());
VERIFY_IS_TRUE(term._buffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._buffer->GetCursor().IsBlinkingAllowed());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsVisible());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsBlinkingAllowed());
term.SetCursorOn(false);
VERIFY_IS_TRUE(term._buffer->GetCursor().IsVisible());
VERIFY_IS_FALSE(term._buffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._buffer->GetCursor().IsBlinkingAllowed());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsVisible());
VERIFY_IS_FALSE(term._mainBuffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsBlinkingAllowed());
term.SetCursorOn(true);
VERIFY_IS_TRUE(term._buffer->GetCursor().IsVisible());
VERIFY_IS_TRUE(term._buffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._buffer->GetCursor().IsBlinkingAllowed());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsVisible());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsBlinkingAllowed());
term.SetCursorVisibility(false);
VERIFY_IS_FALSE(term._buffer->GetCursor().IsVisible());
VERIFY_IS_TRUE(term._buffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._buffer->GetCursor().IsBlinkingAllowed());
VERIFY_IS_FALSE(term._mainBuffer->GetCursor().IsVisible());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsBlinkingAllowed());
term.SetCursorOn(false);
VERIFY_IS_FALSE(term._buffer->GetCursor().IsVisible());
VERIFY_IS_FALSE(term._buffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._buffer->GetCursor().IsBlinkingAllowed());
VERIFY_IS_FALSE(term._mainBuffer->GetCursor().IsVisible());
VERIFY_IS_FALSE(term._mainBuffer->GetCursor().IsOn());
VERIFY_IS_TRUE(term._mainBuffer->GetCursor().IsBlinkingAllowed());
}
void TerminalApiTest::CursorVisibilityViaStateMachine()
@@ -170,7 +170,7 @@ void TerminalApiTest::CursorVisibilityViaStateMachine()
DummyRenderer renderer{ &term };
term.Create({ 100, 100 }, 0, renderer);
auto& tbi = *(term._buffer);
auto& tbi = *(term._mainBuffer);
auto& stateMachine = *(term._stateMachine);
auto& cursor = tbi.GetCursor();
@@ -222,7 +222,7 @@ void TerminalApiTest::CheckDoubleWidthCursor()
DummyRenderer renderer{ &term };
term.Create({ 100, 100 }, 0, renderer);
auto& tbi = *(term._buffer);
auto& tbi = *(term._mainBuffer);
auto& stateMachine = *(term._stateMachine);
auto& cursor = tbi.GetCursor();
@@ -266,7 +266,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlink()
DummyRenderer renderer{ &term };
term.Create({ 100, 100 }, 0, renderer);
auto& tbi = *(term._buffer);
auto& tbi = *(term._mainBuffer);
auto& stateMachine = *(term._stateMachine);
// Process the opening osc 8 sequence
@@ -292,7 +292,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlinkCustomId()
DummyRenderer renderer{ &term };
term.Create({ 100, 100 }, 0, renderer);
auto& tbi = *(term._buffer);
auto& tbi = *(term._mainBuffer);
auto& stateMachine = *(term._stateMachine);
// Process the opening osc 8 sequence
@@ -320,7 +320,7 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlinkCustomIdDifferentUri()
DummyRenderer renderer{ &term };
term.Create({ 100, 100 }, 0, renderer);
auto& tbi = *(term._buffer);
auto& tbi = *(term._mainBuffer);
auto& stateMachine = *(term._stateMachine);
// Process the opening osc 8 sequence

View File

@@ -79,7 +79,7 @@ private:
void TerminalBufferTests::TestSimpleBufferWriting()
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
const auto initialView = term->GetViewport();
@@ -98,7 +98,7 @@ void TerminalBufferTests::TestSimpleBufferWriting()
void TerminalBufferTests::TestWrappingCharByChar()
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
const auto initialView = term->GetViewport();
auto& cursor = termTb.GetCursor();
@@ -137,7 +137,7 @@ void TerminalBufferTests::TestWrappingCharByChar()
void TerminalBufferTests::TestWrappingALongString()
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
const auto initialView = term->GetViewport();
auto& cursor = termTb.GetCursor();
@@ -171,7 +171,7 @@ void TerminalBufferTests::TestWrappingALongString()
void TerminalBufferTests::DontSnapToOutputTest()
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
const auto initialView = term->GetViewport();
@@ -253,7 +253,7 @@ void TerminalBufferTests::DontSnapToOutputTest()
void TerminalBufferTests::_SetTabStops(std::list<short> columns, bool replace)
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
auto& cursor = termTb.GetCursor();
@@ -275,7 +275,7 @@ void TerminalBufferTests::_SetTabStops(std::list<short> columns, bool replace)
std::list<short> TerminalBufferTests::_GetTabStops()
{
std::list<short> columns;
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
const auto initialView = term->GetViewport();
const auto lastColumn = initialView.RightInclusive();
@@ -321,7 +321,7 @@ void TerminalBufferTests::TestResetClearTabStops()
void TerminalBufferTests::TestAddTabStop()
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
auto& cursor = termTb.GetCursor();
@@ -366,7 +366,7 @@ void TerminalBufferTests::TestAddTabStop()
void TerminalBufferTests::TestClearTabStop()
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
auto& cursor = termTb.GetCursor();
@@ -475,7 +475,7 @@ void TerminalBufferTests::TestClearTabStop()
void TerminalBufferTests::TestGetForwardTab()
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
const auto initialView = term->GetViewport();
auto& cursor = termTb.GetCursor();
@@ -545,7 +545,7 @@ void TerminalBufferTests::TestGetForwardTab()
void TerminalBufferTests::TestGetReverseTab()
{
auto& termTb = *term->_buffer;
auto& termTb = *term->_mainBuffer;
auto& termSm = *term->_stateMachine;
auto& cursor = termTb.GetCursor();

View File

@@ -380,6 +380,16 @@ bool VtIo::IsUsingVt() const
return hr;
}
[[nodiscard]] HRESULT VtIo::SwitchScreenBuffer(const bool useAltBuffer)
{
HRESULT hr = S_OK;
if (_pVtRenderEngine)
{
hr = _pVtRenderEngine->SwitchScreenBuffer(useAltBuffer);
}
return hr;
}
void VtIo::CloseInput()
{
// This will release the lock when it goes out of scope

View File

@@ -36,6 +36,8 @@ namespace Microsoft::Console::VirtualTerminal
[[nodiscard]] HRESULT SuppressResizeRepaint();
[[nodiscard]] HRESULT SetCursorPosition(const COORD coordCursor);
[[nodiscard]] HRESULT SwitchScreenBuffer(const bool useAltBuffer);
void CloseInput();
void CloseOutput();

View File

@@ -718,9 +718,8 @@ void SCREEN_INFORMATION::SetViewportSize(const COORD* const pcoordSize)
if (_psiMainBuffer)
{
const auto bufferSize = GetBufferSize().Dimensions();
_psiMainBuffer->SetViewportSize(&bufferSize);
_psiMainBuffer->_fAltWindowChanged = false;
_psiMainBuffer->_deferredPtyResize = til::size{ GetBufferSize().Dimensions() };
}
}
_InternalSetViewportSize(pcoordSize, false, false);
@@ -1489,6 +1488,8 @@ bool SCREEN_INFORMATION::IsMaximizedY() const
// - Success if successful. Invalid parameter if screen buffer size is unexpected. No memory if allocation failed.
[[nodiscard]] NTSTATUS SCREEN_INFORMATION::ResizeTraditional(const COORD coordNewScreenSize)
{
_textBuffer->GetCursor().StartDeferDrawing();
auto endDefer = wil::scope_exit([&]() noexcept { _textBuffer->GetCursor().EndDeferDrawing(); });
return NTSTATUS_FROM_HRESULT(_textBuffer->ResizeTraditional(coordNewScreenSize));
}
@@ -1532,7 +1533,15 @@ bool SCREEN_INFORMATION::IsMaximizedY() const
CommandLine::Instance().EndAllPopups();
const bool fWrapText = gci.GetWrapText();
if (fWrapText)
// GH#3493: Don't reflow the alt buffer.
//
// VTE only rewraps the contents of the (normal screen + its scrollback
// buffer) on a resize event. It doesn't rewrap the contents of the
// alternate screen. The alternate screen is used by applications which
// repaint it after a resize event. So it doesn't really matter. However, in
// that short time window, after resizing the terminal but before the
// application catches up, this prevents vertical lines
if (fWrapText && !_IsAltBuffer())
{
status = ResizeWithReflow(coordNewScreenSize);
}
@@ -1942,6 +1951,15 @@ const SCREEN_INFORMATION& SCREEN_INFORMATION::GetMainBuffer() const
s_RemoveScreenBuffer(psiOldAltBuffer); // this will also delete the old alt buffer
}
// GH#381: When we switch into the alt buffer:
// * flush the current frame, to clear out anything that we prepared for this buffer.
// * Emit a ?1049h/l to the remote side, to let them know that we've switched buffers.
if (gci.IsInVtIoMode() && ServiceLocator::LocateGlobals().pRender)
{
ServiceLocator::LocateGlobals().pRender->TriggerFlush(false);
LOG_IF_FAILED(gci.GetVtIo()->SwitchScreenBuffer(true));
}
::SetActiveScreenBuffer(*psiNewAltBuffer);
// Kind of a hack until we have proper signal channels: If the client app wants window size events, send one for
@@ -1972,6 +1990,22 @@ void SCREEN_INFORMATION::UseMainScreenBuffer()
psiMain->ProcessResizeWindow(&(psiMain->_rcAltSavedClientNew), &(psiMain->_rcAltSavedClientOld));
psiMain->_fAltWindowChanged = false;
}
else if (_psiMainBuffer->_deferredPtyResize.has_value())
{
const COORD newSize = _psiMainBuffer->_deferredPtyResize.value().to_win32_coord();
_psiMainBuffer->SetViewportSize(&newSize);
_psiMainBuffer->_deferredPtyResize = std::nullopt;
}
// GH#381: When we switch into the main buffer:
// * flush the current frame, to clear out anything that we prepared for this buffer.
// * Emit a ?1049h/l to the remote side, to let them know that we've switched buffers.
if (gci.IsInVtIoMode() && ServiceLocator::LocateGlobals().pRender)
{
ServiceLocator::LocateGlobals().pRender->TriggerFlush(false);
LOG_IF_FAILED(gci.GetVtIo()->SwitchScreenBuffer(false));
}
::SetActiveScreenBuffer(*psiMain);
psiMain->UpdateScrollBars(); // The alt had disabled scrollbars, re-enable them

View File

@@ -297,6 +297,8 @@ private:
bool _ignoreLegacyEquivalentVTAttributes;
std::optional<til::size> _deferredPtyResize{ std::nullopt };
#ifdef UNIT_TESTING
friend class TextBufferIteratorTests;
friend class ScreenBufferTests;

View File

@@ -63,12 +63,6 @@ BgfxEngine::BgfxEngine(PVOID SharedViewBase, LONG DisplayHeight, LONG DisplayWid
return S_OK;
}
[[nodiscard]] HRESULT BgfxEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
{
*pForcePaint = false;
return S_FALSE;
}
[[nodiscard]] HRESULT BgfxEngine::PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept
{
*pForcePaint = false;

View File

@@ -39,7 +39,6 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept override;
[[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT StartPaint() noexcept override;

View File

@@ -130,7 +130,7 @@ constexpr HRESULT vec2_narrow(U x, U y, AtlasEngine::vec2<T>& out) noexcept
return S_OK;
}
[[nodiscard]] HRESULT AtlasEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
[[nodiscard]] HRESULT AtlasEngine::InvalidateFlush(_In_ const bool /*circled*/, _Out_ bool* const pForcePaint) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pForcePaint);
*pForcePaint = false;

View File

@@ -33,7 +33,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept override;
[[nodiscard]] HRESULT InvalidateScroll(const COORD* pcoordDelta) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* pForcePaint) noexcept override;
[[nodiscard]] HRESULT InvalidateFlush(_In_ const bool circled, _Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT InvalidateTitle(std::wstring_view proposedTitle) noexcept override;
[[nodiscard]] HRESULT NotifyNewText(const std::wstring_view newText) noexcept override;
[[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override;

View File

@@ -82,3 +82,19 @@ void RenderEngineBase::WaitUntilCanRender() noexcept
// Throttle the render loop a bit by default (~60 FPS), improving throughput.
Sleep(8);
}
// Routine Description:
// - Notifies us that we're about to circle the buffer, giving us a chance to
// force a repaint before the buffer contents are lost.
// - The default implementation of flush, is to do nothing for most renderers.
// Arguments:
// - circled - ignored
// - pForcePaint - Always filled with false
// Return Value:
// - S_FALSE because we don't use this.
[[nodiscard]] HRESULT RenderEngineBase::InvalidateFlush(_In_ const bool /*circled*/, _Out_ bool* const pForcePaint) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pForcePaint);
*pForcePaint = false;
return S_FALSE;
}

View File

@@ -456,14 +456,14 @@ void Renderer::TriggerScroll(const COORD* const pcoordDelta)
// - <none>
// Return Value:
// - <none>
void Renderer::TriggerCircling()
void Renderer::TriggerFlush(const bool circling)
{
const auto rects = _GetSelectionRects();
FOREACH_ENGINE(pEngine)
{
bool fEngineRequestsRepaint = false;
HRESULT hr = pEngine->InvalidateCircling(&fEngineRequestsRepaint);
HRESULT hr = pEngine->InvalidateFlush(circling, &fEngineRequestsRepaint);
LOG_IF_FAILED(hr);
LOG_IF_FAILED(pEngine->InvalidateSelection(rects));

View File

@@ -51,7 +51,7 @@ namespace Microsoft::Console::Render
void TriggerScroll();
void TriggerScroll(const COORD* const pcoordDelta);
void TriggerCircling();
void TriggerFlush(const bool circling);
void TriggerTitleChange();
void TriggerNewTextNotification(const std::wstring_view newText);

View File

@@ -1200,20 +1200,6 @@ try
}
CATCH_RETURN();
// Routine Description:
// - This currently has no effect in this renderer.
// Arguments:
// - pForcePaint - Always filled with false
// Return Value:
// - S_FALSE because we don't use this.
[[nodiscard]] HRESULT DxEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pForcePaint);
*pForcePaint = false;
return S_FALSE;
}
// Routine Description:
// - Gets the area in pixels of the surface we are targeting
// Arguments:

View File

@@ -79,7 +79,6 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept override;
[[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT StartPaint() noexcept override;

View File

@@ -33,7 +33,6 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override;
[[nodiscard]] HRESULT InvalidateCursor(const SMALL_RECT* const psrRegion) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT StartPaint() noexcept override;

View File

@@ -109,21 +109,6 @@ HRESULT GdiEngine::InvalidateAll() noexcept
RETURN_HR(InvalidateSystem(&rc));
}
// Method Description:
// - Notifies us that we're about to circle the buffer, giving us a chance to
// force a repaint before the buffer contents are lost. The GDI renderer
// doesn't care if we lose text - we're only painting visible text anyways,
// so we return false.
// Arguments:
// - Receives a bool indicating if we should force the repaint.
// Return Value:
// - S_FALSE - we succeeded, but the result was false.
HRESULT GdiEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
{
*pForcePaint = false;
return S_FALSE;
}
// Method Description:
// - Notifies us that we're about to be torn down. This gives us a last chance
// to force a repaint before the buffer contents are lost. The GDI renderer

View File

@@ -67,7 +67,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] virtual HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateScroll(const COORD* pcoordDelta) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateAll() noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateCircling(_Out_ bool* pForcePaint) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateFlush(_In_ const bool circled, _Out_ bool* const pForcePaint) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateTitle(std::wstring_view proposedTitle) noexcept = 0;
[[nodiscard]] virtual HRESULT NotifyNewText(const std::wstring_view newText) noexcept = 0;
[[nodiscard]] virtual HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept = 0;

View File

@@ -53,6 +53,8 @@ namespace Microsoft::Console::Render
[[nodiscard]] virtual bool RequiresContinuousRedraw() noexcept override;
[[nodiscard]] HRESULT InvalidateFlush(_In_ const bool circled, _Out_ bool* const pForcePaint) noexcept override;
void WaitUntilCanRender() noexcept override;
protected:

View File

@@ -168,20 +168,6 @@ CATCH_RETURN();
return S_OK;
}
// Routine Description:
// - This currently has no effect in this renderer.
// Arguments:
// - pForcePaint - Always filled with false
// Return Value:
// - S_FALSE because we don't use this.
[[nodiscard]] HRESULT UiaEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
{
RETURN_HR_IF_NULL(E_INVALIDARG, pForcePaint);
*pForcePaint = false;
return S_FALSE;
}
[[nodiscard]] HRESULT UiaEngine::NotifyNewText(const std::wstring_view newText) noexcept
try
{

View File

@@ -46,7 +46,6 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept override;
[[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT NotifyNewText(const std::wstring_view newText) noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(gsl::span<const Cluster> const clusters, const COORD coord, const bool fTrimLeft, const bool lineWrapped) noexcept override;

View File

@@ -434,6 +434,17 @@ using namespace Microsoft::Console::Render;
return _Write("\x1b[?9001h");
}
// Method Description:
// - Send a sequence to the connected terminal to switch to the alternate or main screen buffer.
// Arguments:
// - useAltBuffer: if true, switch to the malt buffer, otherwise to the main buffer.
// Return Value:
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
[[nodiscard]] HRESULT VtEngine::_SwitchScreenBuffer(const bool useAltBuffer) noexcept
{
return _Write(useAltBuffer ? "\x1b[?1049h" : "\x1b[?1049l");
}
// Method Description:
// - Formats and writes a sequence to add a hyperlink to the terminal buffer
// Arguments:

View File

@@ -105,7 +105,7 @@ CATCH_RETURN();
// - Receives a bool indicating if we should force the repaint.
// Return Value:
// - S_OK
[[nodiscard]] HRESULT VtEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
[[nodiscard]] HRESULT VtEngine::InvalidateFlush(_In_ const bool circled, _Out_ bool* const pForcePaint) noexcept
{
// If we're in the middle of a resize request, don't try to immediately start a frame.
if (_inResizeRequest)
@@ -118,7 +118,7 @@ CATCH_RETURN();
// Keep track of the fact that we circled, we'll need to do some work on
// end paint to specifically handle this.
_circled = true;
_circled = circled;
}
_trace.TraceTriggerCircling(*pForcePaint);

View File

@@ -527,3 +527,10 @@ HRESULT VtEngine::RequestWin32Input() noexcept
RETURN_IF_FAILED(_Flush());
return S_OK;
}
HRESULT VtEngine::SwitchScreenBuffer(const bool useAltBuffer) noexcept
{
RETURN_IF_FAILED(_SwitchScreenBuffer(useAltBuffer));
RETURN_IF_FAILED(_Flush());
return S_OK;
}

View File

@@ -56,7 +56,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateSystem(const RECT* prcDirtyClient) noexcept override;
[[nodiscard]] HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* pForcePaint) noexcept override;
[[nodiscard]] HRESULT InvalidateFlush(_In_ const bool circled, _Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(gsl::span<const Cluster> clusters, COORD coord, bool fTrimLeft, bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLineSet lines, COLORREF color, size_t cchLine, COORD coordTarget) noexcept override;
@@ -85,6 +85,7 @@ namespace Microsoft::Console::Render
void SetTerminalCursorTextPosition(const COORD coordCursor) noexcept;
[[nodiscard]] virtual HRESULT ManuallyClearScrollback() noexcept;
[[nodiscard]] HRESULT RequestWin32Input() noexcept;
[[nodiscard]] HRESULT SwitchScreenBuffer(const bool useAltBuffer) noexcept;
protected:
wil::unique_hfile _hFile;
@@ -196,6 +197,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _ListenForDSR() noexcept;
[[nodiscard]] HRESULT _RequestWin32Input() noexcept;
[[nodiscard]] HRESULT _SwitchScreenBuffer(const bool useAltBuffer) noexcept;
[[nodiscard]] virtual HRESULT _MoveCursor(const COORD coord) noexcept = 0;
[[nodiscard]] HRESULT _RgbUpdateDrawingBrushes(const TextAttribute& textAttributes) noexcept;

View File

@@ -191,12 +191,6 @@ bool WddmConEngine::IsInitialized()
return S_OK;
}
[[nodiscard]] HRESULT WddmConEngine::InvalidateCircling(_Out_ bool* const pForcePaint) noexcept
{
*pForcePaint = false;
return S_FALSE;
}
[[nodiscard]] HRESULT WddmConEngine::PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept
{
*pForcePaint = false;

View File

@@ -31,7 +31,6 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept override;
[[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT StartPaint() noexcept override;

View File

@@ -477,4 +477,14 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes
constexpr short s_sDECCOLMSetColumns = 132;
constexpr short s_sDECCOLMResetColumns = 80;
struct MenuEntry
{
std::wstring _name;
std::wstring _comment;
std::wstring _input;
MenuEntry(std::wstring_view name, std::wstring_view comment, std::wstring_view input) :
_name{ name }, _comment{ comment }, _input{ input }
{
}
};
}

View File

@@ -132,6 +132,7 @@ public:
virtual bool EndHyperlink() = 0;
virtual bool DoConEmuAction(const std::wstring_view string) = 0;
virtual bool DoWindowsTerminalAction(const std::wstring_view string) = 0;
virtual StringHandler DownloadDRCS(const size_t fontNumber,
const VTParameter startChar,

View File

@@ -2222,6 +2222,16 @@ bool AdaptDispatch::DoConEmuAction(const std::wstring_view /*string*/) noexcept
return false;
}
// Method Description:
// - Ascribes to the ITermDispatch interface
// - Not actually used in conhost
// Return Value:
// - false (so that the command gets flushed to terminal)
bool AdaptDispatch::DoWindowsTerminalAction(const std::wstring_view /*string*/) noexcept
{
return false;
}
// Method Description:
// - DECDLD - Downloads one or more characters of a dynamically redefinable
// character set (DRCS) with a specified pixel pattern. The pixel array is

View File

@@ -123,6 +123,7 @@ namespace Microsoft::Console::VirtualTerminal
bool EndHyperlink() override;
bool DoConEmuAction(const std::wstring_view string) noexcept override;
bool DoWindowsTerminalAction(const std::wstring_view string) noexcept override;
StringHandler DownloadDRCS(const size_t fontNumber,
const VTParameter startChar,

View File

@@ -125,6 +125,7 @@ public:
bool EndHyperlink() override { return false; }
bool DoConEmuAction(const std::wstring_view /*string*/) override { return false; }
bool DoWindowsTerminalAction(const std::wstring_view /*string*/) override { return false; }
StringHandler DownloadDRCS(const size_t /*fontNumber*/,
const VTParameter /*startChar*/,

View File

@@ -829,6 +829,11 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
success = _dispatch->DoConEmuAction(string);
break;
}
case OscActionCodes::WindowsTerminalAction:
{
success = _dispatch->DoWindowsTerminalAction(string);
break;
}
default:
// If no functions to call, overall dispatch was a failure.
success = false;

View File

@@ -184,7 +184,8 @@ namespace Microsoft::Console::VirtualTerminal
SetClipboard = 52,
ResetForegroundColor = 110, // Not implemented
ResetBackgroundColor = 111, // Not implemented
ResetCursorColor = 112
ResetCursorColor = 112,
WindowsTerminalAction = 9001
};
bool _GetOscTitle(const std::wstring_view string,

View File

@@ -6,7 +6,7 @@
<RootNamespace>Scratch</RootNamespace>
<ProjectName>Scratch</ProjectName>
<TargetName>Scratch</TargetName>
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<Import Project="..\..\common.build.pre.props" />
<ItemGroup>
@@ -21,6 +21,14 @@
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<!-- subsume fmt, one of our dependencies, into contypes. -->
<ProjectReference Include="..\..\dep\fmt\fmt.vcxproj">
<Project>{6bae5851-50d5-4934-8d5e-30361a8a40f3}</Project>
</ProjectReference>
</ItemGroup>
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
<Import Project="..\..\common.build.post.props" />
<Import Project="..\..\common.build.tests.props" />

View File

@@ -1,10 +1,60 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include <windows.h>
#include "../../inc/LibraryIncludes.h"
// #include <windows.h>
// #include <stdio.h>
// #include <iostream>
#define GS L"\x1D"
#define US L"\x1F"
#define DEL L"\x7F"
#define ST L"\x07"
std::wstring trim(const std::wstring& str,
const std::wstring& whitespace = L" \t")
{
const auto strBegin = str.find_first_not_of(whitespace);
if (strBegin == std::wstring::npos)
return L""; // no content
const auto strEnd = str.find_last_not_of(whitespace);
const auto strRange = strEnd - strBegin + 1;
return str.substr(strBegin, strRange);
}
// This wmain exists for help in writing scratch programs while debugging.
int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/)
int __cdecl wmain(int argc, WCHAR* argv[])
{
wprintf(L"\x1b]9001;0\x07");
std::wstring prefix{};
std::wstring suffix{};
for (int i = 0; i < argc; i++)
{
std::wstring arg{ argv[i] };
if (arg == L"--prefix" && (i + 1) <= argc)
{
prefix = argv[i + 1];
i++;
}
else if (arg == L"--suffix" && (i + 1) <= argc)
{
suffix = argv[i + 1];
i++;
}
}
for (std::wstring line; std::getline(std::wcin, line);)
{
std::wstring trimmed{ trim(line) };
std::wstring command{ fmt::format(L"{}{}{}", prefix, trimmed, suffix) };
std::wstring entry{ fmt::format(L"\x1b]9001;1;{}\x7f{}\x7f{}\x7f{}\x07", trimmed, L"a comment", command, L"whatever extras we want") };
wprintf(entry.c_str());
}
return 0;
}