mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-07 06:39:44 +00:00
Compare commits
96 Commits
dev/migrie
...
dev/duhowe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31e62957fc | ||
|
|
2837d8d004 | ||
|
|
52ae8c1124 | ||
|
|
a01500f051 | ||
|
|
c12dc2aa4d | ||
|
|
88c3ef68a5 | ||
|
|
1b09ae3b95 | ||
|
|
7aa7ce2bce | ||
|
|
0f81deb7c0 | ||
|
|
48325f9aca | ||
|
|
8695d9ee4b | ||
|
|
a798a603e1 | ||
|
|
62b34cf6f7 | ||
|
|
f25d258a43 | ||
|
|
cfdea71dc0 | ||
|
|
86928bb48d | ||
|
|
bb4711de54 | ||
|
|
23a02c5218 | ||
|
|
2119164d43 | ||
|
|
b4d37d8c70 | ||
|
|
b4fce27203 | ||
|
|
8ea3cb9972 | ||
|
|
2b851caeed | ||
|
|
aa625098ed | ||
|
|
85ca8f556c | ||
|
|
afefe693df | ||
|
|
7c8f74259d | ||
|
|
0c130fa65b | ||
|
|
3eaa781499 | ||
|
|
bbc14a0baf | ||
|
|
b674ac5c19 | ||
|
|
744ca2450a | ||
|
|
f88ef02c98 | ||
|
|
bcf2422c4d | ||
|
|
7e7a69ff7c | ||
|
|
bfd480b885 | ||
|
|
6d94fbc89f | ||
|
|
42befa7b58 | ||
|
|
97abc3df1d | ||
|
|
8ef18d3c88 | ||
|
|
1f19ed0cd2 | ||
|
|
2a5ce4900f | ||
|
|
ab04067e49 | ||
|
|
18e4e22394 | ||
|
|
33cb0eb05f | ||
|
|
d319d479c7 | ||
|
|
0022898fe8 | ||
|
|
1774cfd843 | ||
|
|
07201d6cd1 | ||
|
|
eebea5129c | ||
|
|
6033ae66c5 | ||
|
|
e4b80e2ef3 | ||
|
|
6803cfb96f | ||
|
|
8f08bb04d0 | ||
|
|
30046dd4a7 | ||
|
|
cacf66860f | ||
|
|
21a9c55752 | ||
|
|
43dbbd590f | ||
|
|
3517a6a3f1 | ||
|
|
d6ac717a48 | ||
|
|
657dd5f43e | ||
|
|
11ad04754d | ||
|
|
51c0b423fb | ||
|
|
d7e24ad6d0 | ||
|
|
a63f060f72 | ||
|
|
5608cf15a3 | ||
|
|
40bc3d7fbc | ||
|
|
00cdacc96b | ||
|
|
54dc2c4432 | ||
|
|
fc0ef37977 | ||
|
|
1da3bc7f1f | ||
|
|
2de475b36a | ||
|
|
c392ade6dd | ||
|
|
975d767d11 | ||
|
|
4f3a639c19 | ||
|
|
e1e6e662f9 | ||
|
|
97dc5c8d75 | ||
|
|
274bdb31da | ||
|
|
5027c8031d | ||
|
|
b3c9f01432 | ||
|
|
c0c284fed3 | ||
|
|
08096b2343 | ||
|
|
f79276b21b | ||
|
|
1ce22a87e6 | ||
|
|
c51bb3a7a6 | ||
|
|
6567201e0e | ||
|
|
bea13bddf1 | ||
|
|
81e2bc98d1 | ||
|
|
446ef22044 | ||
|
|
16aa79d78d | ||
|
|
e2b2d9b92c | ||
|
|
fba4e227f0 | ||
|
|
d21036d313 | ||
|
|
79ef7477f2 | ||
|
|
0973aeab15 | ||
|
|
a94e508010 |
@@ -3,7 +3,7 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"XamlStyler.Console": {
|
||||
"version": "3.2008.4",
|
||||
"version": "3.2206.4",
|
||||
"commands": [
|
||||
"xstyler"
|
||||
]
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/Bug_Report.yml
vendored
4
.github/ISSUE_TEMPLATE/Bug_Report.yml
vendored
@@ -1,6 +1,6 @@
|
||||
name: "Bug report 🐛"
|
||||
description: Report errors or unexpected behavior
|
||||
labels: [Issue-Bug]
|
||||
labels: [Issue-Bug, Needs-Triage]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
@@ -14,7 +14,7 @@ body:
|
||||
label: Windows Terminal version
|
||||
placeholder: "1.7.3651.0"
|
||||
description: |
|
||||
You can find the version in the about dialog, or by running `wt -v` at the commandline.
|
||||
You can find the version in the about dialog, or by running `wt -v` at the commandline (for the Stable/Preview version you’re reporting a bug about).
|
||||
validations:
|
||||
required: false
|
||||
|
||||
|
||||
1
.github/actions/spelling/README.md
vendored
1
.github/actions/spelling/README.md
vendored
@@ -6,6 +6,7 @@ File | Purpose | Format | Info
|
||||
[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)
|
||||
|
||||
2
.github/actions/spelling/advice.md
vendored
2
.github/actions/spelling/advice.md
vendored
@@ -21,7 +21,7 @@ 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 the flagged items are false positives</summary>
|
||||
<details><summary>If the flagged items are :exploding_head: false positives</summary>
|
||||
|
||||
If items relate to a ...
|
||||
* binary file (or some other file you wouldn't want to check at all).
|
||||
|
||||
11
.github/actions/spelling/allow/allow.txt
vendored
11
.github/actions/spelling/allow/allow.txt
vendored
@@ -1,7 +1,7 @@
|
||||
admins
|
||||
allcolors
|
||||
apc
|
||||
Apc
|
||||
apc
|
||||
breadcrumb
|
||||
breadcrumbs
|
||||
bsd
|
||||
@@ -14,8 +14,8 @@ CMMI
|
||||
copyable
|
||||
cybersecurity
|
||||
dalet
|
||||
dcs
|
||||
Dcs
|
||||
dcs
|
||||
dialytika
|
||||
dje
|
||||
downside
|
||||
@@ -34,10 +34,12 @@ gantt
|
||||
gcc
|
||||
geeksforgeeks
|
||||
ghe
|
||||
github
|
||||
gje
|
||||
godbolt
|
||||
hostname
|
||||
hostnames
|
||||
https
|
||||
hyperlink
|
||||
hyperlinking
|
||||
hyperlinks
|
||||
@@ -54,6 +56,7 @@ Llast
|
||||
llvm
|
||||
Lmid
|
||||
locl
|
||||
lol
|
||||
lorem
|
||||
Lorigin
|
||||
maxed
|
||||
@@ -81,6 +84,7 @@ runtimes
|
||||
shcha
|
||||
slnt
|
||||
Sos
|
||||
ssh
|
||||
timeline
|
||||
timelines
|
||||
timestamped
|
||||
@@ -89,6 +93,7 @@ tokenizes
|
||||
tonos
|
||||
toolset
|
||||
tshe
|
||||
ubuntu
|
||||
uiatextrange
|
||||
UIs
|
||||
und
|
||||
@@ -97,5 +102,7 @@ versioned
|
||||
vsdevcmd
|
||||
We'd
|
||||
wildcards
|
||||
XBox
|
||||
YBox
|
||||
yeru
|
||||
zhe
|
||||
|
||||
9
.github/actions/spelling/allow/apis.txt
vendored
9
.github/actions/spelling/allow/apis.txt
vendored
@@ -32,10 +32,10 @@ DERR
|
||||
dlldata
|
||||
DNE
|
||||
DONTADDTORECENT
|
||||
DWMWA
|
||||
DWORDLONG
|
||||
DWMSBT
|
||||
DWMWA
|
||||
DWMWA
|
||||
DWORDLONG
|
||||
endfor
|
||||
ENDSESSION
|
||||
enumset
|
||||
@@ -110,8 +110,8 @@ memchr
|
||||
memicmp
|
||||
MENUCOMMAND
|
||||
MENUDATA
|
||||
MENUITEMINFOW
|
||||
MENUINFO
|
||||
MENUITEMINFOW
|
||||
mmeapi
|
||||
MOUSELEAVE
|
||||
mov
|
||||
@@ -158,8 +158,8 @@ rcx
|
||||
REGCLS
|
||||
RETURNCMD
|
||||
rfind
|
||||
roundf
|
||||
ROOTOWNER
|
||||
roundf
|
||||
RSHIFT
|
||||
SACL
|
||||
schandle
|
||||
@@ -211,6 +211,7 @@ UPDATEINIFILE
|
||||
userenv
|
||||
USEROBJECTFLAGS
|
||||
Viewbox
|
||||
virtualalloc
|
||||
wcsstr
|
||||
wcstoui
|
||||
winmain
|
||||
|
||||
523
.github/actions/spelling/candidate.patterns
vendored
Normal file
523
.github/actions/spelling/candidate.patterns
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
# marker to ignore all code on line
|
||||
^.*/\* #no-spell-check-line \*/.*$
|
||||
# marker for ignoring a comment to the end of the line
|
||||
// #no-spell-check.*$
|
||||
|
||||
# patch hunk comments
|
||||
^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .*
|
||||
# git index header
|
||||
index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
|
||||
|
||||
# cid urls
|
||||
(['"])cid:.*?\g{-1}
|
||||
|
||||
# data url in parens
|
||||
\(data:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
|
||||
# data url in quotes
|
||||
([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
|
||||
# data url
|
||||
data:[-a-zA-Z=;:/0-9+]*,\S*
|
||||
|
||||
# mailto urls
|
||||
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
|
||||
|
||||
# magnet urls
|
||||
magnet:[?=:\w]+
|
||||
|
||||
# magnet urls
|
||||
"magnet:[^"]+"
|
||||
|
||||
# obs:
|
||||
"obs:[^"]*"
|
||||
|
||||
# The `\b` here means a break, it's the fancy way to handle urls, but it makes things harder to read
|
||||
# In this examples content, I'm using a number of different ways to match things to show various approaches
|
||||
# asciinema
|
||||
\basciinema\.org/a/[0-9a-zA-Z]+
|
||||
|
||||
# apple
|
||||
\bdeveloper\.apple\.com/[-\w?=/]+
|
||||
# Apple music
|
||||
\bembed\.music\.apple\.com/fr/playlist/usr-share/[-\w.]+
|
||||
|
||||
# appveyor api
|
||||
\bci\.appveyor\.com/api/projects/status/[0-9a-z]+
|
||||
# appveyor project
|
||||
\bci\.appveyor\.com/project/(?:[^/\s"]*/){2}builds?/\d+/job/[0-9a-z]+
|
||||
|
||||
# Amazon
|
||||
|
||||
# Amazon
|
||||
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
|
||||
# AWS S3
|
||||
\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]*
|
||||
# AWS execute-api
|
||||
\b[0-9a-z]{10}\.execute-api\.[-0-9a-z]+\.amazonaws\.com\b
|
||||
# AWS ELB
|
||||
\b\w+\.[-0-9a-z]+\.elb\.amazonaws\.com\b
|
||||
# AWS SNS
|
||||
\bsns\.[-0-9a-z]+.amazonaws\.com/[-\w/&#%_?:=]*
|
||||
# AWS VPC
|
||||
vpc-\w+
|
||||
|
||||
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
|
||||
# YouTube url
|
||||
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
|
||||
# YouTube music
|
||||
\bmusic\.youtube\.com/youtubei/v1/browse(?:[?&]\w+=[-a-zA-Z0-9?&=_]*)
|
||||
# YouTube tag
|
||||
<\s*youtube\s+id=['"][-a-zA-Z0-9?_]*['"]
|
||||
# YouTube image
|
||||
\bimg\.youtube\.com/vi/[-a-zA-Z0-9?&=_]*
|
||||
# Google Accounts
|
||||
\baccounts.google.com/[-_/?=.:;+%&0-9a-zA-Z]*
|
||||
# Google Analytics
|
||||
\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]*
|
||||
# Google APIs
|
||||
\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+
|
||||
# Google Storage
|
||||
\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|)
|
||||
# Google Calendar
|
||||
\bcalendar\.google\.com/calendar(?:/u/\d+|)/embed\?src=[@./?=\w&%]+
|
||||
\w+\@group\.calendar\.google\.com\b
|
||||
# Google DataStudio
|
||||
\bdatastudio\.google\.com/(?:(?:c/|)u/\d+/|)(?:embed/|)(?:open|reporting|datasources|s)/[-0-9a-zA-Z]+(?:/page/[-0-9a-zA-Z]+|)
|
||||
# The leading `/` here is as opposed to the `\b` above
|
||||
# ... a short way to match `https://` or `http://` since most urls have one of those prefixes
|
||||
# Google Docs
|
||||
/docs\.google\.com/[a-z]+/(?:ccc\?key=\w+|(?:u/\d+|d/(?:e/|)[0-9a-zA-Z_-]+/)?(?:edit\?[-\w=#.]*|/\?[\w=&]*|))
|
||||
# Google Drive
|
||||
\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]*
|
||||
# Google Groups
|
||||
\bgroups\.google\.com/(?:(?:forum/#!|d/)(?:msg|topics?|searchin)|a)/[^/\s"]+/[-a-zA-Z0-9$]+(?:/[-a-zA-Z0-9]+)*
|
||||
# Google Maps
|
||||
\bmaps\.google\.com/maps\?[\w&;=]*
|
||||
# Google themes
|
||||
themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
|
||||
# Google CDN
|
||||
\bclients2\.google(?:usercontent|)\.com[-0-9a-zA-Z/.]*
|
||||
# Goo.gl
|
||||
/goo\.gl/[a-zA-Z0-9]+
|
||||
# Google Chrome Store
|
||||
\bchrome\.google\.com/webstore/detail/[-\w]*(?:/\w*|)
|
||||
# Google Books
|
||||
\bgoogle\.(?:\w{2,4})/books(?:/\w+)*\?[-\w\d=&#.]*
|
||||
# Google Fonts
|
||||
\bfonts\.(?:googleapis|gstatic)\.com/[-/?=:;+&0-9a-zA-Z]*
|
||||
# Google Forms
|
||||
\bforms\.gle/\w+
|
||||
# Google Scholar
|
||||
\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+
|
||||
# Google Colab Research Drive
|
||||
\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]*
|
||||
|
||||
# GitHub SHAs (api)
|
||||
\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b
|
||||
# GitHub SHAs (markdown)
|
||||
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
|
||||
# GitHub SHAs
|
||||
\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b
|
||||
# GitHub wiki
|
||||
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
|
||||
# githubusercontent
|
||||
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
|
||||
# githubassets
|
||||
\bgithubassets.com/[0-9a-f]+(?:[-/\w.]+)
|
||||
# gist github
|
||||
\bgist\.github\.com/[^/\s"]+/[0-9a-f]+
|
||||
# git.io
|
||||
\bgit\.io/[0-9a-zA-Z]+
|
||||
# GitHub JSON
|
||||
"node_id": "[-a-zA-Z=;:/0-9+]*"
|
||||
# Contributor
|
||||
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
|
||||
# GHSA
|
||||
GHSA(?:-[0-9a-z]{4}){3}
|
||||
|
||||
# GitLab commit
|
||||
\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b
|
||||
# GitLab merge requests
|
||||
\bgitlab\.[^/\s"]*/\S+/\S+/-/merge_requests/\d+/diffs#[0-9a-f]{40}\b
|
||||
# GitLab uploads
|
||||
\bgitlab\.[^/\s"]*/uploads/[-a-zA-Z=;:/0-9+]*
|
||||
# GitLab commits
|
||||
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
|
||||
|
||||
# binanace
|
||||
accounts.binance.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
|
||||
|
||||
# bitbucket diff
|
||||
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+
|
||||
# bitbucket repositories commits
|
||||
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
|
||||
# bitbucket commits
|
||||
\bbitbucket\.org/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
|
||||
|
||||
# bit.ly
|
||||
\bbit\.ly/\w+
|
||||
|
||||
# bitrise
|
||||
\bapp\.bitrise\.io/app/[0-9a-f]*/[\w.?=&]*
|
||||
|
||||
# bootstrapcdn.com
|
||||
\bbootstrapcdn\.com/[-./\w]+
|
||||
|
||||
# cdn.cloudflare.com
|
||||
\bcdnjs\.cloudflare\.com/[./\w]+
|
||||
|
||||
# circleci
|
||||
\bcircleci\.com/gh(?:/[^/\s"]+){1,5}.[a-z]+\?[-0-9a-zA-Z=&]+
|
||||
|
||||
# gitter
|
||||
\bgitter\.im(?:/[^/\s"]+){2}\?at=[0-9a-f]+
|
||||
|
||||
# gravatar
|
||||
\bgravatar\.com/avatar/[0-9a-f]+
|
||||
|
||||
# ibm
|
||||
[a-z.]*ibm\.com/[-_#=:%!?~.\\/\d\w]*
|
||||
|
||||
# imgur
|
||||
\bimgur\.com/[^.]+
|
||||
|
||||
# Internet Archive
|
||||
\barchive\.org/web/\d+/(?:[-\w.?,'/\\+&%$#_:]*)
|
||||
|
||||
# discord
|
||||
/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,}
|
||||
|
||||
# Disqus
|
||||
\bdisqus\.com/[-\w/%.()!?&=_]*
|
||||
|
||||
# medium link
|
||||
\blink\.medium\.com/[a-zA-Z0-9]+
|
||||
# medium
|
||||
\bmedium\.com/\@?[^/\s"]+/[-\w]+
|
||||
|
||||
# microsoft
|
||||
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
|
||||
# powerbi
|
||||
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
|
||||
# vs devops
|
||||
\bvisualstudio.com(?::443|)/[-\w/?=%&.]*
|
||||
# microsoft store
|
||||
\bmicrosoft\.com/store/apps/\w+
|
||||
|
||||
# mvnrepository.com
|
||||
\bmvnrepository\.com/[-0-9a-z./]+
|
||||
|
||||
# now.sh
|
||||
/[0-9a-z-.]+\.now\.sh\b
|
||||
|
||||
# oracle
|
||||
\bdocs\.oracle\.com/[-0-9a-zA-Z./_?#&=]*
|
||||
|
||||
# chromatic.com
|
||||
/\S+.chromatic.com\S*[")]
|
||||
|
||||
# codacy
|
||||
\bapi\.codacy\.com/project/badge/Grade/[0-9a-f]+
|
||||
|
||||
# compai
|
||||
\bcompai\.pub/v1/png/[0-9a-f]+
|
||||
|
||||
# mailgun api
|
||||
\.api\.mailgun\.net/v3/domains/[0-9a-z]+\.mailgun.org/messages/[0-9a-zA-Z=@]*
|
||||
# mailgun
|
||||
\b[0-9a-z]+.mailgun.org
|
||||
|
||||
# /message-id/
|
||||
/message-id/[-\w@./%]+
|
||||
|
||||
# Reddit
|
||||
\breddit\.com/r/[/\w_]*
|
||||
|
||||
# requestb.in
|
||||
\brequestb\.in/[0-9a-z]+
|
||||
|
||||
# sched
|
||||
\b[a-z0-9]+\.sched\.com\b
|
||||
|
||||
# Slack url
|
||||
slack://[a-zA-Z0-9?&=]+
|
||||
# Slack
|
||||
\bslack\.com/[-0-9a-zA-Z/_~?&=.]*
|
||||
# Slack edge
|
||||
\bslack-edge\.com/[-a-zA-Z0-9?&=%./]+
|
||||
# Slack images
|
||||
\bslack-imgs\.com/[-a-zA-Z0-9?&=%.]+
|
||||
|
||||
# shields.io
|
||||
\bshields\.io/[-\w/%?=&.:+;,]*
|
||||
|
||||
# stackexchange -- https://stackexchange.com/feeds/sites
|
||||
\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/)
|
||||
|
||||
# Sentry
|
||||
[0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b
|
||||
|
||||
# Twitter markdown
|
||||
\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\)
|
||||
# Twitter hashtag
|
||||
\btwitter\.com/hashtag/[\w?_=&]*
|
||||
# Twitter status
|
||||
\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)
|
||||
# Twitter profile images
|
||||
\btwimg\.com/profile_images/[_\w./]*
|
||||
# Twitter media
|
||||
\btwimg\.com/media/[-_\w./?=]*
|
||||
# Twitter link shortened
|
||||
\bt\.co/\w+
|
||||
|
||||
# facebook
|
||||
\bfburl\.com/[0-9a-z_]+
|
||||
# facebook CDN
|
||||
\bfbcdn\.net/[\w/.,]*
|
||||
# facebook watch
|
||||
\bfb\.watch/[0-9A-Za-z]+
|
||||
|
||||
# dropbox
|
||||
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
|
||||
|
||||
# ipfs protocol
|
||||
ipfs://[0-9a-z]*
|
||||
# ipfs url
|
||||
/ipfs/[0-9a-z]*
|
||||
|
||||
# w3
|
||||
\bw3\.org/[-0-9a-zA-Z/#.]+
|
||||
|
||||
# loom
|
||||
\bloom\.com/embed/[0-9a-f]+
|
||||
|
||||
# regex101
|
||||
\bregex101\.com/r/[^/\s"]+/\d+
|
||||
|
||||
# figma
|
||||
\bfigma\.com/file(?:/[0-9a-zA-Z]+/)+
|
||||
|
||||
# freecodecamp.org
|
||||
\bfreecodecamp\.org/[-\w/.]+
|
||||
|
||||
# image.tmdb.org
|
||||
\bimage\.tmdb\.org/[/\w.]+
|
||||
|
||||
# mermaid
|
||||
\bmermaid\.ink/img/[-\w]+|\bmermaid-js\.github\.io/mermaid-live-editor/#/edit/[-\w]+
|
||||
|
||||
# Wikipedia
|
||||
\ben\.wikipedia\.org/wiki/[-\w%.#]+
|
||||
|
||||
# gitweb
|
||||
[^"\s]+/gitweb/\S+;h=[0-9a-f]+
|
||||
|
||||
# HyperKitty lists
|
||||
/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/
|
||||
|
||||
# lists
|
||||
/thread\.html/[^"\s]+
|
||||
|
||||
# list-management
|
||||
\blist-manage\.com/subscribe(?:[?&](?:u|id)=[0-9a-f]+)+
|
||||
|
||||
# kubectl.kubernetes.io/last-applied-configuration
|
||||
"kubectl.kubernetes.io/last-applied-configuration": ".*"
|
||||
|
||||
# pgp
|
||||
\bgnupg\.net/pks/lookup[?&=0-9a-zA-Z]*
|
||||
|
||||
# Spotify
|
||||
\bopen\.spotify\.com/embed/playlist/\w+
|
||||
|
||||
# Mastodon
|
||||
\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]*
|
||||
|
||||
# scastie
|
||||
\bscastie\.scala-lang\.org/[^/]+/\w+
|
||||
|
||||
# images.unsplash.com
|
||||
\bimages\.unsplash\.com/(?:(?:flagged|reserve)/|)[-\w./%?=%&.;]+
|
||||
|
||||
# pastebin
|
||||
\bpastebin\.com/[\w/]+
|
||||
|
||||
# heroku
|
||||
\b\w+\.heroku\.com/source/archive/\w+
|
||||
|
||||
# quip
|
||||
\b\w+\.quip\.com/\w+(?:(?:#|/issues/)\w+)?
|
||||
|
||||
# badgen.net
|
||||
\bbadgen\.net/badge/[^")\]'\s]+
|
||||
|
||||
# statuspage.io
|
||||
\w+\.statuspage\.io\b
|
||||
|
||||
# media.giphy.com
|
||||
\bmedia\.giphy\.com/media/[^/]+/[\w.?&=]+
|
||||
|
||||
# tinyurl
|
||||
\btinyurl\.com/\w+
|
||||
|
||||
# getopts
|
||||
\bgetopts\s+(?:"[^"]+"|'[^']+')
|
||||
|
||||
# ANSI color codes
|
||||
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
|
||||
|
||||
# URL escaped characters
|
||||
\%[0-9A-F][A-F]
|
||||
# IPv6
|
||||
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
|
||||
# c99 hex digits (not the full format, just one I've seen)
|
||||
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
|
||||
# Punycode
|
||||
\bxn--[-0-9a-z]+
|
||||
# sha
|
||||
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
|
||||
# sha-... -- uses a fancy capture
|
||||
(['"]|")[0-9a-f]{40,}\g{-1}
|
||||
# hex runs
|
||||
\b[0-9a-fA-F]{16,}\b
|
||||
# hex in url queries
|
||||
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
|
||||
# ssh
|
||||
(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,}
|
||||
|
||||
# PGP
|
||||
\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b
|
||||
# GPG keys
|
||||
\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b
|
||||
# Well known gpg keys
|
||||
.well-known/openpgpkey/[\w./]+
|
||||
|
||||
# uuid:
|
||||
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
|
||||
# hex digits including css/html color classes:
|
||||
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
|
||||
# integrity
|
||||
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
|
||||
|
||||
# https://www.gnu.org/software/groff/manual/groff.html
|
||||
# man troff content
|
||||
\\f[BCIPR]
|
||||
# '
|
||||
\\\(aq
|
||||
|
||||
# .desktop mime types
|
||||
^MimeTypes?=.*$
|
||||
# .desktop localized entries
|
||||
^[A-Z][a-z]+\[[a-z]+\]=.*$
|
||||
# Localized .desktop content
|
||||
Name\[[^\]]+\]=.*
|
||||
|
||||
# IServiceProvider
|
||||
\bI(?=(?:[A-Z][a-z]{2,})+\b)
|
||||
|
||||
# crypt
|
||||
"\$2[ayb]\$.{56}"
|
||||
|
||||
# scrypt / argon
|
||||
\$(?:scrypt|argon\d+[di]*)\$\S+
|
||||
|
||||
# Input to GitHub JSON
|
||||
content: "[-a-zA-Z=;:/0-9+]*="
|
||||
|
||||
# Python stringprefix / binaryprefix
|
||||
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
|
||||
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
|
||||
|
||||
# Regular expressions for (P|p)assword
|
||||
\([A-Z]\|[a-z]\)[a-z]+
|
||||
|
||||
# JavaScript regular expressions
|
||||
# javascript test regex
|
||||
/.*/[gim]*\.test\(
|
||||
# javascript match regex
|
||||
\.match\(/[^/\s"]*/[gim]*\s*
|
||||
# javascript match regex
|
||||
\.match\(/\\[b].*?/[gim]*\s*\)(?:;|$)
|
||||
# javascript regex
|
||||
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
|
||||
# javascript replace regex
|
||||
\.replace\(/[^/\s"]*/[gim]*\s*,
|
||||
|
||||
# Go regular expressions
|
||||
regexp?\.MustCompile\(`[^`]*`\)
|
||||
|
||||
# sed regular expressions
|
||||
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
|
||||
|
||||
# go install
|
||||
go install(?:\s+[a-z]+\.[-@\w/.]+)+
|
||||
|
||||
# kubernetes pod status lists
|
||||
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
|
||||
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
|
||||
|
||||
# kubectl - pods in CrashLoopBackOff
|
||||
\w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+
|
||||
|
||||
# kubernetes object suffix
|
||||
-[0-9a-f]{10}-\w{5}\s
|
||||
|
||||
# posthog secrets
|
||||
posthog\.init\((['"])phc_[^"',]+\g{-1},
|
||||
|
||||
# xcode
|
||||
|
||||
# xcodeproject scenes
|
||||
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
|
||||
|
||||
# xcode api botches
|
||||
customObjectInstantitationMethod
|
||||
|
||||
# font awesome classes
|
||||
\.fa-[-a-z0-9]+
|
||||
|
||||
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
|
||||
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
|
||||
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
|
||||
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
|
||||
## You could manually change `(?i)X...` to use `[Xx]...`
|
||||
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
|
||||
# Lorem
|
||||
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
|
||||
|
||||
# Non-English
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
|
||||
|
||||
# French
|
||||
# This corpus only had capital letters, but you probably want lowercase ones as well.
|
||||
\b[LN]'+[a-z]{2,}\b
|
||||
|
||||
# latex
|
||||
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
|
||||
|
||||
# the negative lookahead here is to allow catching 'templatesz' as a misspelling
|
||||
# but to otherwise recognize a Windows path with \templates\foo.template or similar:
|
||||
\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
|
||||
# ignore long runs of a single character:
|
||||
\b([A-Za-z])\g{-1}{3,}\b
|
||||
# Note that the next example is no longer necessary if you are using
|
||||
# to match a string starting with a `#`, use a character-class:
|
||||
[#]backwards
|
||||
# version suffix <word>v#
|
||||
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
|
||||
# Compiler flags (Scala)
|
||||
(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
# Compiler flags
|
||||
#(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
|
||||
# Compiler flags (linker)
|
||||
,-B
|
||||
# curl arguments
|
||||
\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
|
||||
# set arguments
|
||||
\bset(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)*
|
||||
# tar arguments
|
||||
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
|
||||
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
|
||||
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
|
||||
# macOS temp folders
|
||||
/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/
|
||||
38
.github/actions/spelling/excludes.txt
vendored
38
.github/actions/spelling/excludes.txt
vendored
@@ -2,14 +2,14 @@
|
||||
(?:(?i)\.png$)
|
||||
(?:^|/)(?i)COPYRIGHT
|
||||
(?:^|/)(?i)LICEN[CS]E
|
||||
(?:^|/)3rdparty/
|
||||
(?:^|/)dirs$
|
||||
(?:^|/)go\.mod$
|
||||
(?:^|/)go\.sum$
|
||||
(?:^|/)package(?:-lock|)\.json$
|
||||
(?:^|/)sources(?:|\.dep)$
|
||||
(?:^|/)vendor/
|
||||
ignore$
|
||||
SUMS$
|
||||
\.a$
|
||||
\.ai$
|
||||
\.avi$
|
||||
\.bmp$
|
||||
@@ -20,6 +20,8 @@ SUMS$
|
||||
\.crt$
|
||||
\.csr$
|
||||
\.dll$
|
||||
\.docx?$
|
||||
\.drawio$
|
||||
\.DS_Store$
|
||||
\.eot$
|
||||
\.eps$
|
||||
@@ -31,6 +33,7 @@ SUMS$
|
||||
\.icns$
|
||||
\.ico$
|
||||
\.jar$
|
||||
\.jks$
|
||||
\.jpeg$
|
||||
\.jpg$
|
||||
\.key$
|
||||
@@ -41,6 +44,7 @@ SUMS$
|
||||
\.mod$
|
||||
\.mp3$
|
||||
\.mp4$
|
||||
\.o$
|
||||
\.ocf$
|
||||
\.otf$
|
||||
\.pbxproj$
|
||||
@@ -48,22 +52,41 @@ SUMS$
|
||||
\.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/
|
||||
@@ -90,12 +113,5 @@ SUMS$
|
||||
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
|
||||
^src/types/ut_types/UtilsTests.cpp$
|
||||
^tools/ReleaseEngineering/ServicingPipeline.ps1$
|
||||
^\.github/actions/spelling/
|
||||
^\.github/fabricbot.json$
|
||||
^\.gitignore$
|
||||
^\Q.github/workflows/spelling.yml\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$
|
||||
ignore$
|
||||
SUMS$
|
||||
|
||||
7
.github/actions/spelling/expect/alphabet.txt
vendored
7
.github/actions/spelling/expect/alphabet.txt
vendored
@@ -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
|
||||
|
||||
696
.github/actions/spelling/expect/expect.txt
vendored
696
.github/actions/spelling/expect/expect.txt
vendored
File diff suppressed because it is too large
Load Diff
2
.github/actions/spelling/expect/web.txt
vendored
2
.github/actions/spelling/expect/web.txt
vendored
@@ -1,5 +1,3 @@
|
||||
http
|
||||
www
|
||||
WCAG
|
||||
winui
|
||||
appshellintegration
|
||||
|
||||
30
.github/actions/spelling/line_forbidden.patterns
vendored
30
.github/actions/spelling/line_forbidden.patterns
vendored
@@ -1,3 +1,11 @@
|
||||
# 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
|
||||
|
||||
@@ -16,6 +24,12 @@
|
||||
# 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
|
||||
|
||||
@@ -27,10 +41,22 @@
|
||||
\b[Nn]o[nt][- ]existent\b
|
||||
|
||||
# s.b. preexisting
|
||||
[Pp]re-existing
|
||||
[Pp]re[- ]existing
|
||||
|
||||
# s.b. preempt
|
||||
[Pp]re[- ]empt\b
|
||||
|
||||
# s.b. preemptively
|
||||
[Pp]re-emptively
|
||||
[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
|
||||
|
||||
57
.github/actions/spelling/patterns/patterns.txt
vendored
57
.github/actions/spelling/patterns/patterns.txt
vendored
@@ -27,13 +27,68 @@ ROY\sG\.\sBIV
|
||||
# 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
|
||||
(?:[\\@](?: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
|
||||
|
||||
|
||||
27
.github/actions/spelling/reject.txt
vendored
27
.github/actions/spelling/reject.txt
vendored
@@ -1,31 +1,12 @@
|
||||
benefitting
|
||||
occurences?
|
||||
Sorce
|
||||
^attache$
|
||||
^attacher$
|
||||
^attachers$
|
||||
benefitting
|
||||
occurences?
|
||||
^dependan.*
|
||||
^oer$
|
||||
^spae$
|
||||
^spae-man$
|
||||
^spaebook$
|
||||
^spaecraft$
|
||||
^spaed$
|
||||
^spaedom$
|
||||
^spaeing$
|
||||
^spaeings$
|
||||
^spaeman$
|
||||
^spaer$
|
||||
^Spaerobee$
|
||||
^spaes$
|
||||
^spaewife$
|
||||
^spaewoman$
|
||||
^spaework$
|
||||
^spaewright$
|
||||
Sorce
|
||||
^[Ss]pae.*
|
||||
^untill$
|
||||
^untilling$
|
||||
^wether$
|
||||
^wether.*
|
||||
^wethers$
|
||||
^wetherteg$
|
||||
^[Ss]pae.*
|
||||
|
||||
1
.github/workflows/addToProject.yml
vendored
1
.github/workflows/addToProject.yml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
issues:
|
||||
types:
|
||||
- labeled
|
||||
- unlabeled
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
|
||||
106
.github/workflows/spelling2.yml
vendored
106
.github/workflows/spelling2.yml
vendored
@@ -1,10 +1,57 @@
|
||||
# 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: ["**"]
|
||||
branches:
|
||||
- "**"
|
||||
tags-ignore:
|
||||
- "**"
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "**"
|
||||
tags-ignore:
|
||||
- "**"
|
||||
types:
|
||||
- 'opened'
|
||||
- 'reopened'
|
||||
- 'synchronize'
|
||||
issue_comment:
|
||||
types:
|
||||
- 'created'
|
||||
|
||||
jobs:
|
||||
spelling:
|
||||
@@ -24,23 +71,64 @@ jobs:
|
||||
steps:
|
||||
- name: check-spelling
|
||||
id: spelling
|
||||
uses: check-spelling/check-spelling@v0.0.20
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
with:
|
||||
suppress_push_for_open_pull_request: 1
|
||||
checkout: true
|
||||
check_file_names: 1
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
post_comment: 0
|
||||
use_magic_file: 1
|
||||
extra_dictionary_limit: 10
|
||||
extra_dictionaries:
|
||||
cspell:software-terms/src/software-terms.txt
|
||||
cspell:python/src/python/python-lib.txt
|
||||
cspell:node/node.txt
|
||||
cspell:cpp/src/stdlib-c.txt
|
||||
cspell:cpp/src/stdlib-cpp.txt
|
||||
cspell:fullstack/fullstack.txt
|
||||
cspell:filetypes/filetypes.txt
|
||||
cspell:html/html.txt
|
||||
cspell:cpp/src/compiler-msvc.txt
|
||||
cspell:python/src/common/extra.txt
|
||||
cspell:powershell/powershell.txt
|
||||
cspell:aws/aws.txt
|
||||
cspell:cpp/src/lang-keywords.txt
|
||||
cspell:npm/npm.txt
|
||||
cspell:dotnet/dotnet.txt
|
||||
cspell:python/src/python/python.txt
|
||||
cspell:css/css.txt
|
||||
cspell:cpp/src/stdlib-cmath.txt
|
||||
check_extra_dictionaries: ''
|
||||
|
||||
comment:
|
||||
name: Report
|
||||
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
|
||||
pull-requests: write
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name != 'push'
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.20
|
||||
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 }}
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "dep/gsl"]
|
||||
path = dep/gsl
|
||||
url = https://github.com/microsoft/gsl
|
||||
[submodule "dep/wil"]
|
||||
path = dep/wil
|
||||
url = https://github.com/microsoft/wil
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"Microsoft.Net.Component.4.5.TargetingPack",
|
||||
"Microsoft.VisualStudio.Component.DiagnosticTools",
|
||||
"Microsoft.VisualStudio.Component.Debugger.JustInTime",
|
||||
"Microsoft.VisualStudio.Component.Windows11SDK.22000",
|
||||
"Microsoft.VisualStudio.Component.Windows11SDK.22621",
|
||||
"Microsoft.VisualStudio.ComponentGroup.UWP.Support",
|
||||
"Microsoft.VisualStudio.Component.VC.CoreIde",
|
||||
"Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
|
||||
|
||||
@@ -643,7 +643,8 @@ Global
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -661,7 +662,8 @@ Global
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{DCF55140-EF6A-4736-A403-957E4F7430BB}.Release|x64.Build.0 = Release|x64
|
||||
@@ -2308,7 +2310,8 @@ Global
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -2325,7 +2328,8 @@ Global
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|x64.ActiveCfg = Release|x64
|
||||
{48D21369-3D7B-4431-9967-24E81292CF63}.Release|x64.Build.0 = Release|x64
|
||||
@@ -3313,7 +3317,8 @@ Global
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.Build.0 = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.Build.0 = Debug|x64
|
||||
@@ -3333,7 +3338,8 @@ Global
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.Build.0 = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.ActiveCfg = Release|x64
|
||||
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.Build.0 = Release|x64
|
||||
|
||||
@@ -67,7 +67,7 @@ the latest Terminal release by installing the `Microsoft.WindowsTerminal`
|
||||
package:
|
||||
|
||||
```powershell
|
||||
winget install --id=Microsoft.WindowsTerminal -e
|
||||
winget install --id Microsoft.WindowsTerminal -e
|
||||
```
|
||||
|
||||
#### Via Chocolatey (unofficial)
|
||||
@@ -289,7 +289,7 @@ If you would like to ask a question that you feel doesn't warrant an issue
|
||||
app](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development)
|
||||
to locally install and run Windows Terminal
|
||||
* You must have [PowerShell 7 or later](https://github.com/PowerShell/PowerShell/releases/latest) installed
|
||||
* You must have the [Windows 11 (10.0.22000.0)
|
||||
* You must have the [Windows 11 (10.0.22621.0)
|
||||
SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/)
|
||||
installed
|
||||
* You must have at least [VS
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"msbuild-sdks": {
|
||||
"Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20277.5"
|
||||
"Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.22525.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
jobs:
|
||||
- job: CodeFormatCheck
|
||||
displayName: Proper Code Formatting Check
|
||||
pool: { vmImage: windows-2019 }
|
||||
pool: { vmImage: windows-2022 }
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
|
||||
@@ -43,9 +43,9 @@ jobs:
|
||||
filename: 'set'
|
||||
|
||||
- task: NuGetToolInstaller@0
|
||||
displayName: 'Use NuGet 5.2.0'
|
||||
displayName: 'Use NuGet 6.3.0'
|
||||
inputs:
|
||||
versionSpec: 5.2.0
|
||||
versionSpec: 6.3.0
|
||||
|
||||
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
|
||||
displayName: 'NuGet restore build/Helix/packages.config'
|
||||
|
||||
@@ -27,9 +27,9 @@ jobs:
|
||||
displayName: 'Retrieve VC tools directory'
|
||||
|
||||
- task: NuGetToolInstaller@0
|
||||
displayName: 'Use NuGet 5.2.0'
|
||||
displayName: 'Use NuGet 6.3.0'
|
||||
inputs:
|
||||
versionSpec: 5.2.0
|
||||
versionSpec: 6.3.0
|
||||
|
||||
- task: NuGetAuthenticate@0
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
steps:
|
||||
- task: NuGetToolInstaller@0
|
||||
displayName: 'Use NuGet 5.2.0'
|
||||
displayName: 'Use NuGet 6.3.0'
|
||||
inputs:
|
||||
versionSpec: 5.2.0
|
||||
versionSpec: 6.3.0
|
||||
|
||||
- task: NuGetAuthenticate@0
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Param(
|
||||
[Parameter(HelpMessage="Path to makeappx.exe")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x86\MakeAppx.exe"
|
||||
$MakeAppxPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\MakeAppx.exe"
|
||||
)
|
||||
|
||||
If ($null -Eq (Get-Item $MakeAppxPath -EA:SilentlyContinue)) {
|
||||
|
||||
@@ -8,7 +8,7 @@ Param(
|
||||
[Parameter(HelpMessage="Path to Windows Kit")]
|
||||
[ValidateScript({Test-Path $_ -Type Leaf})]
|
||||
[string]
|
||||
$WindowsKitPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0"
|
||||
$WindowsKitPath = "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
@@ -13,6 +13,10 @@ Licensed under the MIT license.
|
||||
#define CIS_EVENT_TYPE_FOCUS (1)
|
||||
#define CIS_EVENT_TYPE_FOCUS_ACK (2)
|
||||
|
||||
#define CIS_MSG_TYPE_MAPVIRTUALKEY (0)
|
||||
#define CIS_MSG_TYPE_VKKEYSCAN (1)
|
||||
#define CIS_MSG_TYPE_GETKEYSTATE (2)
|
||||
|
||||
#define CIS_MSG_TYPE_GETDISPLAYSIZE (3)
|
||||
#define CIS_MSG_TYPE_GETFONTSIZE (4)
|
||||
#define CIS_MSG_TYPE_SETCURSOR (5)
|
||||
@@ -31,6 +35,22 @@ typedef struct {
|
||||
UCHAR Type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
UINT Code;
|
||||
UINT MapType;
|
||||
UINT ReturnValue;
|
||||
} MapVirtualKeyParams;
|
||||
|
||||
struct {
|
||||
WCHAR Character;
|
||||
SHORT ReturnValue;
|
||||
} VkKeyScanParams;
|
||||
|
||||
struct {
|
||||
int VirtualKey;
|
||||
SHORT ReturnValue;
|
||||
} GetKeyStateParams;
|
||||
|
||||
struct {
|
||||
CD_IO_DISPLAY_SIZE DisplaySize;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
[Amalgamated](https://github.com/open-source-parsers/jsoncpp/wiki/Amalgamated)
|
||||
from source commit
|
||||
[6aba23f](https://github.com/open-source-parsers/jsoncpp/commit/6aba23f4a8628d599a9ef7fa4811c4ff6e4070e2),
|
||||
release 1.9.3.
|
||||
[5defb4e](https://github.com/open-source-parsers/jsoncpp/commit/5defb4ed1a4293b8e2bf641e16b156fb9de498cc),
|
||||
release 1.9.5.
|
||||
|
||||
> Generating amalgamated source and header JsonCpp is provided with a script to
|
||||
> generate a single header and a single source file to ease inclusion into an
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/open-source-parsers/jsoncpp",
|
||||
"commitHash": "6aba23f4a8628d599a9ef7fa4811c4ff6e4070e2"
|
||||
"commitHash": "5defb4ed1a4293b8e2bf641e16b156fb9de498cc"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,28 +7,28 @@
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
|
||||
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
@@ -94,10 +94,10 @@ license you like.
|
||||
// 3. /CMakeLists.txt
|
||||
// IMPORTANT: also update the SOVERSION!!
|
||||
|
||||
#define JSONCPP_VERSION_STRING "1.9.3"
|
||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
||||
#define JSONCPP_VERSION_MAJOR 1
|
||||
#define JSONCPP_VERSION_MINOR 9
|
||||
#define JSONCPP_VERSION_PATCH 3
|
||||
#define JSONCPP_VERSION_PATCH 5
|
||||
#define JSONCPP_VERSION_QUALIFIER
|
||||
#define JSONCPP_VERSION_HEXA \
|
||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||
@@ -162,11 +162,10 @@ public:
|
||||
* Release memory which was allocated for N items at pointer P.
|
||||
*
|
||||
* The memory block is filled with zeroes before being released.
|
||||
* The pointer argument is tagged as "volatile" to prevent the
|
||||
* compiler optimizing out this critical step.
|
||||
*/
|
||||
void deallocate(volatile pointer p, size_type n) {
|
||||
std::memset(p, 0, n * sizeof(T));
|
||||
void deallocate(pointer p, size_type n) {
|
||||
// memset_s is used because memset may be optimized away by the compiler
|
||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||
// free using "global operator delete"
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
@@ -6,28 +6,28 @@
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
|
||||
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
@@ -93,10 +93,10 @@ license you like.
|
||||
// 3. /CMakeLists.txt
|
||||
// IMPORTANT: also update the SOVERSION!!
|
||||
|
||||
#define JSONCPP_VERSION_STRING "1.9.3"
|
||||
#define JSONCPP_VERSION_STRING "1.9.5"
|
||||
#define JSONCPP_VERSION_MAJOR 1
|
||||
#define JSONCPP_VERSION_MINOR 9
|
||||
#define JSONCPP_VERSION_PATCH 3
|
||||
#define JSONCPP_VERSION_PATCH 5
|
||||
#define JSONCPP_VERSION_QUALIFIER
|
||||
#define JSONCPP_VERSION_HEXA \
|
||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||
@@ -161,11 +161,10 @@ public:
|
||||
* Release memory which was allocated for N items at pointer P.
|
||||
*
|
||||
* The memory block is filled with zeroes before being released.
|
||||
* The pointer argument is tagged as "volatile" to prevent the
|
||||
* compiler optimizing out this critical step.
|
||||
*/
|
||||
void deallocate(volatile pointer p, size_type n) {
|
||||
std::memset(p, 0, n * sizeof(T));
|
||||
void deallocate(pointer p, size_type n) {
|
||||
// memset_s is used because memset may be optimized away by the compiler
|
||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||
// free using "global operator delete"
|
||||
::operator delete(p);
|
||||
}
|
||||
@@ -575,7 +574,7 @@ public:
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4251 4275)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push, 8)
|
||||
@@ -788,10 +787,10 @@ private:
|
||||
CZString(ArrayIndex index);
|
||||
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
||||
CZString(CZString const& other);
|
||||
CZString(CZString&& other);
|
||||
CZString(CZString&& other) noexcept;
|
||||
~CZString();
|
||||
CZString& operator=(const CZString& other);
|
||||
CZString& operator=(CZString&& other);
|
||||
CZString& operator=(CZString&& other) noexcept;
|
||||
|
||||
bool operator<(CZString const& other) const;
|
||||
bool operator==(CZString const& other) const;
|
||||
@@ -867,14 +866,15 @@ public:
|
||||
Value(const StaticString& value);
|
||||
Value(const String& value);
|
||||
Value(bool value);
|
||||
Value(std::nullptr_t ptr) = delete;
|
||||
Value(const Value& other);
|
||||
Value(Value&& other);
|
||||
Value(Value&& other) noexcept;
|
||||
~Value();
|
||||
|
||||
/// \note Overwrite existing comments. To preserve comments, use
|
||||
/// #swapPayload().
|
||||
Value& operator=(const Value& other);
|
||||
Value& operator=(Value&& other);
|
||||
Value& operator=(Value&& other) noexcept;
|
||||
|
||||
/// Swap everything.
|
||||
void swap(Value& other);
|
||||
@@ -1159,9 +1159,9 @@ private:
|
||||
public:
|
||||
Comments() = default;
|
||||
Comments(const Comments& that);
|
||||
Comments(Comments&& that);
|
||||
Comments(Comments&& that) noexcept;
|
||||
Comments& operator=(const Comments& that);
|
||||
Comments& operator=(Comments&& that);
|
||||
Comments& operator=(Comments&& that) noexcept;
|
||||
bool has(CommentPlacement slot) const;
|
||||
String get(CommentPlacement slot) const;
|
||||
void set(CommentPlacement slot, String comment);
|
||||
@@ -1442,8 +1442,8 @@ public:
|
||||
* because the returned references/pointers can be used
|
||||
* to change state of the base class.
|
||||
*/
|
||||
reference operator*() { return deref(); }
|
||||
pointer operator->() { return &deref(); }
|
||||
reference operator*() const { return const_cast<reference>(deref()); }
|
||||
pointer operator->() const { return const_cast<pointer>(&deref()); }
|
||||
};
|
||||
|
||||
inline void swap(Value& a, Value& b) { a.swap(b); }
|
||||
@@ -1506,8 +1506,7 @@ namespace Json {
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
|
||||
class JSONCPP_DEPRECATED(
|
||||
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
|
||||
class JSON_API Reader {
|
||||
public:
|
||||
using Char = char;
|
||||
using Location = const Char*;
|
||||
@@ -1524,13 +1523,13 @@ public:
|
||||
};
|
||||
|
||||
/** \brief Constructs a Reader allowing all features for parsing.
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
|
||||
Reader();
|
||||
|
||||
/** \brief Constructs a Reader allowing the specified feature set for parsing.
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
|
||||
Reader(const Features& features);
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
@@ -1797,6 +1796,9 @@ public:
|
||||
* - `"allowSpecialFloats": false or true`
|
||||
* - If true, special float values (NaNs and infinities) are allowed and
|
||||
* their values are lossfree restorable.
|
||||
* - `"skipBom": false or true`
|
||||
* - If true, if the input starts with the Unicode byte order mark (BOM),
|
||||
* it is skipped.
|
||||
*
|
||||
* You can examine 'settings_` yourself to see the defaults. You can also
|
||||
* write and read them just like any JSON Value.
|
||||
@@ -2000,6 +2002,8 @@ public:
|
||||
* - Number of precision digits for formatting of real values.
|
||||
* - "precisionType": "significant"(default) or "decimal"
|
||||
* - Type of precision for formatting of real values.
|
||||
* - "emitUTF8": false or true
|
||||
* - If true, outputs raw UTF8 strings instead of escaping them.
|
||||
|
||||
* You can examine 'settings_` yourself
|
||||
* to see the defaults. You can also write and read them just like any
|
||||
@@ -2035,7 +2039,7 @@ public:
|
||||
/** \brief Abstract class for writers.
|
||||
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
||||
*/
|
||||
class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer {
|
||||
class JSON_API Writer {
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
@@ -2055,7 +2059,7 @@ public:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
|
||||
class JSON_API FastWriter
|
||||
: public Writer {
|
||||
public:
|
||||
FastWriter();
|
||||
@@ -2115,7 +2119,7 @@ private:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
||||
class JSON_API
|
||||
StyledWriter : public Writer {
|
||||
public:
|
||||
StyledWriter();
|
||||
@@ -2184,7 +2188,7 @@ private:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
||||
class JSON_API
|
||||
StyledStreamWriter {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -6,28 +6,28 @@
|
||||
// //////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
|
||||
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
@@ -202,14 +202,18 @@ template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
|
||||
* Return iterator that would be the new end of the range [begin,end), if we
|
||||
* were to delete zeros in the end of string, but not the last zero before '.'.
|
||||
*/
|
||||
template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
|
||||
template <typename Iter>
|
||||
Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
|
||||
for (; begin != end; --end) {
|
||||
if (*(end - 1) != '0') {
|
||||
return end;
|
||||
}
|
||||
// Don't delete the last zero before the decimal point.
|
||||
if (begin != (end - 1) && *(end - 2) == '.') {
|
||||
return end;
|
||||
if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
|
||||
if (precision) {
|
||||
return end;
|
||||
}
|
||||
return end - 2;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
@@ -338,8 +342,7 @@ bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
|
||||
|
||||
// Since String is reference-counted, this at least does not
|
||||
// create an extra copy.
|
||||
String doc;
|
||||
std::getline(is, doc, static_cast<char> EOF);
|
||||
String doc(std::istreambuf_iterator<char>(is), {});
|
||||
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
|
||||
}
|
||||
|
||||
@@ -1409,8 +1412,11 @@ bool OurReader::readToken(Token& token) {
|
||||
if (features_.allowSingleQuotes_) {
|
||||
token.type_ = tokenString;
|
||||
ok = readStringSingleQuote();
|
||||
break;
|
||||
} // else fall through
|
||||
} else {
|
||||
// If we don't allow single quotes, this is a failure case.
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
token.type_ = tokenComment;
|
||||
ok = readComment();
|
||||
@@ -2152,7 +2158,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const {
|
||||
if (valid_keys.count(key))
|
||||
continue;
|
||||
if (invalid)
|
||||
(*invalid)[std::move(key)] = *si;
|
||||
(*invalid)[key] = *si;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -2667,7 +2673,7 @@ Value::CZString::CZString(const CZString& other) {
|
||||
storage_.length_ = other.storage_.length_;
|
||||
}
|
||||
|
||||
Value::CZString::CZString(CZString&& other)
|
||||
Value::CZString::CZString(CZString&& other) noexcept
|
||||
: cstr_(other.cstr_), index_(other.index_) {
|
||||
other.cstr_ = nullptr;
|
||||
}
|
||||
@@ -2693,7 +2699,7 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value::CZString& Value::CZString::operator=(CZString&& other) {
|
||||
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
|
||||
cstr_ = other.cstr_;
|
||||
index_ = other.index_;
|
||||
other.cstr_ = nullptr;
|
||||
@@ -2841,7 +2847,7 @@ Value::Value(const Value& other) {
|
||||
dupMeta(other);
|
||||
}
|
||||
|
||||
Value::Value(Value&& other) {
|
||||
Value::Value(Value&& other) noexcept {
|
||||
initBasic(nullValue);
|
||||
swap(other);
|
||||
}
|
||||
@@ -2856,7 +2862,7 @@ Value& Value::operator=(const Value& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value& Value::operator=(Value&& other) {
|
||||
Value& Value::operator=(Value&& other) noexcept {
|
||||
other.swap(*this);
|
||||
return *this;
|
||||
}
|
||||
@@ -3320,7 +3326,8 @@ void Value::resize(ArrayIndex newSize) {
|
||||
if (newSize == 0)
|
||||
clear();
|
||||
else if (newSize > oldSize)
|
||||
this->operator[](newSize - 1);
|
||||
for (ArrayIndex i = oldSize; i < newSize; ++i)
|
||||
(*this)[i];
|
||||
else {
|
||||
for (ArrayIndex index = newSize; index < oldSize; ++index) {
|
||||
value_.map_->erase(index);
|
||||
@@ -3781,14 +3788,15 @@ bool Value::isObject() const { return type() == objectValue; }
|
||||
Value::Comments::Comments(const Comments& that)
|
||||
: ptr_{cloneUnique(that.ptr_)} {}
|
||||
|
||||
Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
|
||||
Value::Comments::Comments(Comments&& that) noexcept
|
||||
: ptr_{std::move(that.ptr_)} {}
|
||||
|
||||
Value::Comments& Value::Comments::operator=(const Comments& that) {
|
||||
ptr_ = cloneUnique(that.ptr_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value::Comments& Value::Comments::operator=(Comments&& that) {
|
||||
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
|
||||
ptr_ = std::move(that.ptr_);
|
||||
return *this;
|
||||
}
|
||||
@@ -3804,13 +3812,11 @@ String Value::Comments::get(CommentPlacement slot) const {
|
||||
}
|
||||
|
||||
void Value::Comments::set(CommentPlacement slot, String comment) {
|
||||
if (!ptr_) {
|
||||
if (slot >= CommentPlacement::numberOfCommentPlacement)
|
||||
return;
|
||||
if (!ptr_)
|
||||
ptr_ = std::unique_ptr<Array>(new Array());
|
||||
}
|
||||
// check comments array boundry.
|
||||
if (slot < CommentPlacement::numberOfCommentPlacement) {
|
||||
(*ptr_)[slot] = std::move(comment);
|
||||
}
|
||||
(*ptr_)[slot] = std::move(comment);
|
||||
}
|
||||
|
||||
void Value::setComment(String comment, CommentPlacement placement) {
|
||||
@@ -4124,7 +4130,7 @@ Value& Path::make(Value& root) const {
|
||||
|
||||
#if !defined(isnan)
|
||||
// IEEE standard states that NaN values will not compare to themselves
|
||||
#define isnan(x) (x != x)
|
||||
#define isnan(x) ((x) != (x))
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
@@ -4210,16 +4216,18 @@ String valueToString(double value, bool useSpecialFloats,
|
||||
|
||||
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
|
||||
|
||||
// strip the zero padding from the right
|
||||
if (precisionType == PrecisionType::decimalPlaces) {
|
||||
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
|
||||
}
|
||||
|
||||
// try to ensure we preserve the fact that this was given to us as a double on
|
||||
// input
|
||||
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
|
||||
buffer += ".0";
|
||||
}
|
||||
|
||||
// strip the zero padding from the right
|
||||
if (precisionType == PrecisionType::decimalPlaces) {
|
||||
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision),
|
||||
buffer.end());
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
} // namespace
|
||||
@@ -4231,11 +4239,11 @@ String valueToString(double value, unsigned int precision,
|
||||
|
||||
String valueToString(bool value) { return value ? "true" : "false"; }
|
||||
|
||||
static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
|
||||
static bool doesAnyCharRequireEscaping(char const* s, size_t n) {
|
||||
assert(s || !n);
|
||||
|
||||
return std::any_of(s, s + n, [](unsigned char c) {
|
||||
return c == '\\' || c == '"' || !std::isprint(c);
|
||||
return c == '\\' || c == '"' || c < 0x20 || c > 0x7F;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4326,12 +4334,12 @@ static void appendHex(String& result, unsigned ch) {
|
||||
result.append("\\u").append(toHex16Bit(ch));
|
||||
}
|
||||
|
||||
static String valueToQuotedStringN(const char* value, unsigned length,
|
||||
static String valueToQuotedStringN(const char* value, size_t length,
|
||||
bool emitUTF8 = false) {
|
||||
if (value == nullptr)
|
||||
return "";
|
||||
|
||||
if (!isAnyCharRequiredQuoting(value, length))
|
||||
if (!doesAnyCharRequireEscaping(value, length))
|
||||
return String("\"") + value + "\"";
|
||||
// We have to walk value and escape any special characters.
|
||||
// Appending to String is not efficient, but this should be rare.
|
||||
@@ -4404,7 +4412,7 @@ static String valueToQuotedStringN(const char* value, unsigned length,
|
||||
}
|
||||
|
||||
String valueToQuotedString(const char* value) {
|
||||
return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
|
||||
return valueToQuotedStringN(value, strlen(value));
|
||||
}
|
||||
|
||||
// Class Writer
|
||||
@@ -4453,7 +4461,7 @@ void FastWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
|
||||
document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
|
||||
break;
|
||||
}
|
||||
case booleanValue:
|
||||
@@ -4476,8 +4484,7 @@ void FastWriter::writeValue(const Value& value) {
|
||||
const String& name = *it;
|
||||
if (it != members.begin())
|
||||
document_ += ',';
|
||||
document_ += valueToQuotedStringN(name.data(),
|
||||
static_cast<unsigned>(name.length()));
|
||||
document_ += valueToQuotedStringN(name.data(), name.length());
|
||||
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
|
||||
writeValue(value[name]);
|
||||
}
|
||||
@@ -4522,7 +4529,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -4563,7 +4570,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
}
|
||||
|
||||
void StyledWriter::writeArrayValue(const Value& value) {
|
||||
unsigned size = value.size();
|
||||
size_t size = value.size();
|
||||
if (size == 0)
|
||||
pushValue("[]");
|
||||
else {
|
||||
@@ -4572,7 +4579,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
||||
writeWithIndent("[");
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index = 0;
|
||||
ArrayIndex index = 0;
|
||||
for (;;) {
|
||||
const Value& childValue = value[index];
|
||||
writeCommentBeforeValue(childValue);
|
||||
@@ -4595,7 +4602,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
||||
{
|
||||
assert(childValues_.size() == size);
|
||||
document_ += "[ ";
|
||||
for (unsigned index = 0; index < size; ++index) {
|
||||
for (size_t index = 0; index < size; ++index) {
|
||||
if (index > 0)
|
||||
document_ += ", ";
|
||||
document_ += childValues_[index];
|
||||
@@ -4740,7 +4747,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -5014,8 +5021,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
|
||||
emitUTF8_));
|
||||
pushValue(
|
||||
valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -5038,8 +5045,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
String const& name = *it;
|
||||
Value const& childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(valueToQuotedStringN(
|
||||
name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
|
||||
writeWithIndent(
|
||||
valueToQuotedStringN(name.data(), name.length(), emitUTF8_));
|
||||
*sout_ << colonSymbol_;
|
||||
writeValue(childValue);
|
||||
if (++it == members.end()) {
|
||||
@@ -5273,7 +5280,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const {
|
||||
if (valid_keys.count(key))
|
||||
continue;
|
||||
if (invalid)
|
||||
(*invalid)[std::move(key)] = *si;
|
||||
(*invalid)[key] = *si;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ Here's the AppxManifest we're using:
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22621.0" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
</Dependencies>
|
||||
@@ -517,7 +517,7 @@ This is because of a few key lines we already put in the appxmanifest:
|
||||
|
||||
```xml
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22000.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.22621.0" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
</Dependencies>
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
},
|
||||
"intenseTextStyle": {
|
||||
"default": "bright",
|
||||
"description": "Controls how 'intense' text is rendered. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"description": "Controls how 'intense' text is rendered when unfocused. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"enum": [
|
||||
"none",
|
||||
"bold",
|
||||
@@ -244,7 +244,7 @@
|
||||
"default": 12,
|
||||
"description": "Size of the font in points.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
"type": "number"
|
||||
},
|
||||
"weight": {
|
||||
"default": "normal",
|
||||
@@ -2252,7 +2252,7 @@
|
||||
"default": 12,
|
||||
"description": "[deprecated] Define 'size' within the 'font' object instead.",
|
||||
"minimum": 1,
|
||||
"type": "integer",
|
||||
"type": "number",
|
||||
"deprecated": true
|
||||
},
|
||||
"fontWeight": {
|
||||
@@ -2283,6 +2283,17 @@
|
||||
],
|
||||
"deprecated": true
|
||||
},
|
||||
"intenseTextStyle": {
|
||||
"default": "bright",
|
||||
"description": "Controls how 'intense' text is rendered. Values are \"bold\", \"bright\", \"all\" and \"none\"",
|
||||
"enum": [
|
||||
"none",
|
||||
"bold",
|
||||
"bright",
|
||||
"all"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"foreground": {
|
||||
"$ref": "#/$defs/Color",
|
||||
"default": "#cccccc",
|
||||
@@ -2350,7 +2361,8 @@
|
||||
"description": "Defines the visibility of the scrollbar.",
|
||||
"enum": [
|
||||
"visible",
|
||||
"hidden"
|
||||
"hidden",
|
||||
"always"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#ifdef USE_INTERVAL_TREE_NAMESPACE
|
||||
namespace interval_tree
|
||||
|
||||
@@ -8,7 +8,7 @@ That provenance file is automatically read and inventoried by Microsoft systems
|
||||
|
||||
## What should be done to update this in the future?
|
||||
|
||||
1. Go to ekg/intervaltreerepository on GitHub.
|
||||
1. Go to the ekg/intervaltree repository on GitHub.
|
||||
2. Take the file IntervalTree.h wholesale and drop it into the directory here.
|
||||
3. Don't change anything about it.
|
||||
4. Validate that the license in the root of the repository didn't change and update it if so. It is sitting in the same directory as this readme.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/ekg/intervaltree",
|
||||
"commitHash": "b90527f9e6d51cd36ecbb50429e4524d3a418ea5"
|
||||
"commitHash": "aa5937755000f1cd007402d03b6f7ce4427c5d21"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/kimwalisch/libpopcnt",
|
||||
"commitHash": "043a99fba31121a70bcb2f589faa17f534ae6085"
|
||||
"commitHash": "c49987e90e56191c399cab881ab87b5daecc9b8e"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
||||
<ProjectGuid>{96274800-9574-423E-892A-909FBE2AC8BE}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>EchoCon</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.17763.0</WindowsTargetPlatformMinVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22000.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -136,12 +136,12 @@
|
||||
<!-- **END VC LIBS HACK** -->
|
||||
|
||||
<!-- This is required to get the package dependency in the AppXManifest. -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
|
||||
|
||||
@@ -147,12 +147,12 @@
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -91,12 +91,12 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.1" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -144,12 +144,12 @@
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.1\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.UI.Xaml.2.7.3\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
</Target>
|
||||
|
||||
<!-- Override GetPackagingOutputs to roll up all our dependencies.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210825.3" targetFramework="native" />
|
||||
<package id="Microsoft.Toolkit.Win32.UI.XamlApplication" version="6.1.3" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.1" targetFramework="native" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.7.3" targetFramework="native" />
|
||||
<package id="Microsoft.VCRTForwarders.140" version="1.0.4" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -5,11 +5,6 @@
|
||||
#include "MidiAudio.hpp"
|
||||
#include "../terminal/parser/stateMachine.hpp"
|
||||
|
||||
#include <dsound.h>
|
||||
|
||||
#pragma comment(lib, "dxguid.lib")
|
||||
#pragma comment(lib, "dsound.lib")
|
||||
|
||||
using Microsoft::WRL::ComPtr;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@@ -18,66 +13,48 @@ using namespace std::chrono_literals;
|
||||
constexpr auto WAVE_SIZE = 16u;
|
||||
constexpr auto WAVE_DATA = std::array<byte, WAVE_SIZE>{ 128, 159, 191, 223, 255, 223, 191, 159, 128, 96, 64, 32, 0, 32, 64, 96 };
|
||||
|
||||
MidiAudio::MidiAudio(HWND windowHandle)
|
||||
void MidiAudio::_initialize(HWND windowHandle) noexcept
|
||||
{
|
||||
if (SUCCEEDED(DirectSoundCreate8(nullptr, &_directSound, nullptr)))
|
||||
_hwnd = windowHandle;
|
||||
_directSoundModule.reset(LoadLibraryExW(L"dsound.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32));
|
||||
if (_directSoundModule)
|
||||
{
|
||||
if (SUCCEEDED(_directSound->SetCooperativeLevel(windowHandle, DSSCL_NORMAL)))
|
||||
if (const auto createFunction = GetProcAddressByFunctionDeclaration(_directSoundModule.get(), DirectSoundCreate8))
|
||||
{
|
||||
_createBuffers();
|
||||
if (SUCCEEDED(createFunction(nullptr, &_directSound, nullptr)))
|
||||
{
|
||||
if (SUCCEEDED(_directSound->SetCooperativeLevel(windowHandle, DSSCL_NORMAL)))
|
||||
{
|
||||
_createBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MidiAudio::~MidiAudio() noexcept
|
||||
void MidiAudio::BeginSkip() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
#pragma warning(suppress : 26447)
|
||||
// We acquire the lock here so the class isn't destroyed while in use.
|
||||
// If this throws, we'll catch it, so the C26447 warning is bogus.
|
||||
const auto lock = std::unique_lock{ _inUseMutex };
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// If the lock fails, we'll just have to live with the consequences.
|
||||
}
|
||||
_skip.SetEvent();
|
||||
}
|
||||
|
||||
void MidiAudio::Initialize()
|
||||
void MidiAudio::EndSkip() noexcept
|
||||
{
|
||||
_shutdownFuture = _shutdownPromise.get_future();
|
||||
_skip.ResetEvent();
|
||||
}
|
||||
|
||||
void MidiAudio::Shutdown()
|
||||
{
|
||||
// Once the shutdown promise is set, any note that is playing will stop
|
||||
// immediately, and the Unlock call will exit the thread ASAP.
|
||||
_shutdownPromise.set_value();
|
||||
}
|
||||
|
||||
void MidiAudio::Lock()
|
||||
{
|
||||
_inUseMutex.lock();
|
||||
}
|
||||
|
||||
void MidiAudio::Unlock()
|
||||
{
|
||||
// We need to check the shutdown status before releasing the mutex,
|
||||
// because after that the class could be destroyed.
|
||||
const auto shutdownStatus = _shutdownFuture.wait_for(0s);
|
||||
_inUseMutex.unlock();
|
||||
// If the wait didn't timeout, that means the shutdown promise was set,
|
||||
// so we need to exit the thread ASAP by throwing an exception.
|
||||
if (shutdownStatus != std::future_status::timeout)
|
||||
{
|
||||
throw Microsoft::Console::VirtualTerminal::StateMachine::ShutdownException{};
|
||||
}
|
||||
}
|
||||
|
||||
void MidiAudio::PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept
|
||||
void MidiAudio::PlayNote(HWND windowHandle, const int noteNumber, const int velocity, const std::chrono::milliseconds duration) noexcept
|
||||
try
|
||||
{
|
||||
if (_skip.is_signaled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_hwnd != windowHandle)
|
||||
{
|
||||
_initialize(windowHandle);
|
||||
}
|
||||
|
||||
const auto& buffer = _buffers.at(_activeBufferIndex);
|
||||
if (velocity && buffer)
|
||||
{
|
||||
@@ -100,10 +77,10 @@ try
|
||||
buffer->SetCurrentPosition((_lastBufferPosition + 12) % WAVE_SIZE);
|
||||
}
|
||||
|
||||
// By waiting on the shutdown future with the duration of the note, we'll
|
||||
// either be paused for the appropriate amount of time, or we'll break out
|
||||
// of the wait early if we've been shutdown.
|
||||
_shutdownFuture.wait_for(duration);
|
||||
// By waiting on the skip event with a maximum duration of the note, we'll
|
||||
// either be paused for the appropriate amount of time, or we'll break out early
|
||||
// because BeginSkip() was called. This happens for Ctrl+C or during shutdown.
|
||||
_skip.wait(::base::saturated_cast<DWORD>(duration.count()));
|
||||
|
||||
if (velocity && buffer)
|
||||
{
|
||||
|
||||
@@ -12,8 +12,6 @@ Abstract:
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
|
||||
struct IDirectSound8;
|
||||
struct IDirectSoundBuffer;
|
||||
@@ -21,26 +19,20 @@ struct IDirectSoundBuffer;
|
||||
class MidiAudio
|
||||
{
|
||||
public:
|
||||
MidiAudio(HWND windowHandle);
|
||||
MidiAudio(const MidiAudio&) = delete;
|
||||
MidiAudio(MidiAudio&&) = delete;
|
||||
MidiAudio& operator=(const MidiAudio&) = delete;
|
||||
MidiAudio& operator=(MidiAudio&&) = delete;
|
||||
~MidiAudio() noexcept;
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
void PlayNote(const int noteNumber, const int velocity, const std::chrono::microseconds duration) noexcept;
|
||||
void BeginSkip() noexcept;
|
||||
void EndSkip() noexcept;
|
||||
void PlayNote(HWND windowHandle, const int noteNumber, const int velocity, const std::chrono::milliseconds duration) noexcept;
|
||||
|
||||
private:
|
||||
void _initialize(HWND windowHandle) noexcept;
|
||||
void _createBuffers() noexcept;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDirectSound8> _directSound;
|
||||
std::array<Microsoft::WRL::ComPtr<IDirectSoundBuffer>, 2> _buffers;
|
||||
wil::slim_event_manual_reset _skip;
|
||||
|
||||
HWND _hwnd = nullptr;
|
||||
wil::unique_hmodule _directSoundModule;
|
||||
wil::com_ptr<IDirectSound8> _directSound;
|
||||
std::array<wil::com_ptr<IDirectSoundBuffer>, 2> _buffers;
|
||||
size_t _activeBufferIndex = 0;
|
||||
DWORD _lastBufferPosition = 0;
|
||||
std::promise<void> _shutdownPromise;
|
||||
std::future<void> _shutdownFuture;
|
||||
std::mutex _inUseMutex;
|
||||
};
|
||||
|
||||
3
src/audio/midi/lib/sources.dep
Normal file
3
src/audio/midi/lib/sources.dep
Normal file
@@ -0,0 +1,3 @@
|
||||
BUILD_PASS1_CONSUMES= \
|
||||
onecore\windows\vcpkg|PASS1 \
|
||||
|
||||
@@ -25,7 +25,9 @@ Abstract:
|
||||
#endif
|
||||
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#include <mmeapi.h>
|
||||
#include <dsound.h>
|
||||
|
||||
// clang-format on
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "AttrRow.hpp"
|
||||
|
||||
// Routine Description:
|
||||
// - constructor
|
||||
// Arguments:
|
||||
// - cchRowWidth - the length of the default text attribute
|
||||
// - attr - the default text attribute
|
||||
// Return Value:
|
||||
// - constructed object
|
||||
ATTR_ROW::ATTR_ROW(const til::CoordType width, const TextAttribute attr) :
|
||||
_data(gsl::narrow_cast<uint16_t>(width), attr) {}
|
||||
|
||||
// Routine Description:
|
||||
// - Sets all properties of the ATTR_ROW to default values
|
||||
// Arguments:
|
||||
// - attr - The default text attributes to use on text in this row.
|
||||
void ATTR_ROW::Reset(const TextAttribute attr)
|
||||
{
|
||||
_data.replace(0, _data.size(), attr);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Takes an existing row of attributes, and changes the length so that it fills the NewWidth.
|
||||
// If the new size is bigger, then the last attr is extended to fill the NewWidth.
|
||||
// If the new size is smaller, the runs are cut off to fit.
|
||||
// Arguments:
|
||||
// - oldWidth - The original width of the row.
|
||||
// - newWidth - The new width of the row.
|
||||
// Return Value:
|
||||
// - <none>, throws exceptions on failures.
|
||||
void ATTR_ROW::Resize(const til::CoordType newWidth)
|
||||
{
|
||||
_data.resize_trailing_extent(gsl::narrow<uint16_t>(newWidth));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - returns a copy of the TextAttribute at the specified column
|
||||
// Arguments:
|
||||
// - column - the column to get the attribute for
|
||||
// Return Value:
|
||||
// - the text attribute at column
|
||||
// Note:
|
||||
// - will throw on error
|
||||
TextAttribute ATTR_ROW::GetAttrByColumn(const til::CoordType column) const
|
||||
{
|
||||
return _data.at(gsl::narrow<uint16_t>(column));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Finds the hyperlink IDs present in this row and returns them
|
||||
// Return value:
|
||||
// - The hyperlink IDs present in this row
|
||||
std::vector<uint16_t> ATTR_ROW::GetHyperlinks() const
|
||||
{
|
||||
std::vector<uint16_t> ids;
|
||||
for (const auto& run : _data.runs())
|
||||
{
|
||||
if (run.value.IsHyperlink())
|
||||
{
|
||||
ids.emplace_back(run.value.GetHyperlinkId());
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Sets the attributes (colors) of all character positions from the given position through the end of the row.
|
||||
// Arguments:
|
||||
// - iStart - Starting index position within the row
|
||||
// - attr - Attribute (color) to fill remaining characters with
|
||||
// Return Value:
|
||||
// - <none>
|
||||
bool ATTR_ROW::SetAttrToEnd(const til::CoordType beginIndex, const TextAttribute attr)
|
||||
{
|
||||
_data.replace(gsl::narrow<uint16_t>(beginIndex), _data.size(), attr);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Replaces all runs in the row with the given toBeReplacedAttr with the new
|
||||
// attribute replaceWith.
|
||||
// Arguments:
|
||||
// - toBeReplacedAttr - the attribute to replace in this row.
|
||||
// - replaceWith - the new value for the matching runs' attributes.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAttribute& replaceWith)
|
||||
{
|
||||
_data.replace_values(toBeReplacedAttr, replaceWith);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Takes an attribute, and merges it into this row from beginIndex (inclusive) to endIndex (exclusive).
|
||||
// - For example, if the current row was [{4, BLUE}], the merge arguments were
|
||||
// { beginIndex = 1, endIndex = 3, newAttr = RED }, then the row would modified to be
|
||||
// [{ 1, BLUE}, {2, RED}, {1, BLUE}].
|
||||
// Arguments:
|
||||
// - beginIndex, endIndex: The [beginIndex, endIndex) range that's to be replaced with newAttr.
|
||||
// - newAttr: The attribute to merge into this row.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void ATTR_ROW::Replace(const til::CoordType beginIndex, const til::CoordType endIndex, const TextAttribute& newAttr)
|
||||
{
|
||||
_data.replace(gsl::narrow<uint16_t>(beginIndex), gsl::narrow<uint16_t>(endIndex), newAttr);
|
||||
}
|
||||
|
||||
ATTR_ROW::const_iterator ATTR_ROW::begin() const noexcept
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
ATTR_ROW::const_iterator ATTR_ROW::end() const noexcept
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
ATTR_ROW::const_iterator ATTR_ROW::cbegin() const noexcept
|
||||
{
|
||||
return _data.cbegin();
|
||||
}
|
||||
|
||||
ATTR_ROW::const_iterator ATTR_ROW::cend() const noexcept
|
||||
{
|
||||
return _data.cend();
|
||||
}
|
||||
|
||||
bool operator==(const ATTR_ROW& a, const ATTR_ROW& b) noexcept
|
||||
{
|
||||
return a._data == b._data;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- AttrRow.hpp
|
||||
|
||||
Abstract:
|
||||
- contains data structure for the attributes of one row of screen buffer
|
||||
|
||||
Author(s):
|
||||
- Michael Niksa (miniksa) 10-Apr-2014
|
||||
- Paul Campbell (paulcam) 10-Apr-2014
|
||||
|
||||
Revision History:
|
||||
- From components of output.h/.c
|
||||
by Therese Stowell (ThereseS) 1990-1991
|
||||
- Pulled into its own file from textBuffer.hpp/cpp (AustDi, 2017)
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "til/rle.h"
|
||||
#include "TextAttribute.hpp"
|
||||
|
||||
class ATTR_ROW final
|
||||
{
|
||||
using rle_vector = til::small_rle<TextAttribute, uint16_t, 1>;
|
||||
|
||||
public:
|
||||
using const_iterator = rle_vector::const_iterator;
|
||||
|
||||
ATTR_ROW(til::CoordType width, TextAttribute attr);
|
||||
|
||||
~ATTR_ROW() = default;
|
||||
|
||||
ATTR_ROW(const ATTR_ROW&) = default;
|
||||
ATTR_ROW& operator=(const ATTR_ROW&) = default;
|
||||
ATTR_ROW(ATTR_ROW&&)
|
||||
noexcept = default;
|
||||
ATTR_ROW& operator=(ATTR_ROW&&) noexcept = default;
|
||||
|
||||
TextAttribute GetAttrByColumn(til::CoordType column) const;
|
||||
std::vector<uint16_t> GetHyperlinks() const;
|
||||
|
||||
bool SetAttrToEnd(til::CoordType beginIndex, TextAttribute attr);
|
||||
void ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAttribute& replaceWith);
|
||||
void Resize(til::CoordType newWidth);
|
||||
void Replace(til::CoordType beginIndex, til::CoordType endIndex, const TextAttribute& newAttr);
|
||||
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
friend bool operator==(const ATTR_ROW& a, const ATTR_ROW& b) noexcept;
|
||||
friend class ROW;
|
||||
|
||||
private:
|
||||
void Reset(const TextAttribute attr);
|
||||
|
||||
rle_vector _data;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class CommonState;
|
||||
#endif
|
||||
};
|
||||
@@ -1,281 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include "CharRow.hpp"
|
||||
#include "unicode.hpp"
|
||||
#include "Row.hpp"
|
||||
|
||||
// Routine Description:
|
||||
// - constructor
|
||||
// Arguments:
|
||||
// - rowWidth - the size (in wchar_t) of the char and attribute rows
|
||||
// - pParent - the parent ROW
|
||||
// Return Value:
|
||||
// - instantiated object
|
||||
// Note: will through if unable to allocate char/attribute buffers
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26447) // small_vector's constructor says it can throw but it should not given how we use it. This suppresses this error for the AuditMode build.
|
||||
CharRow::CharRow(til::CoordType rowWidth, ROW* const pParent) noexcept :
|
||||
_data(rowWidth, value_type()),
|
||||
_pParent{ FAIL_FAST_IF_NULL(pParent) }
|
||||
{
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
// Routine Description:
|
||||
// - gets the size of the row, in glyph cells
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - the size of the row
|
||||
til::CoordType CharRow::size() const noexcept
|
||||
{
|
||||
return gsl::narrow_cast<til::CoordType>(_data.size());
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Sets all properties of the CharRowBase to default values
|
||||
// Arguments:
|
||||
// - sRowWidth - The width of the row.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CharRow::Reset() noexcept
|
||||
{
|
||||
for (auto& cell : _data)
|
||||
{
|
||||
cell.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - resizes the width of the CharRowBase
|
||||
// Arguments:
|
||||
// - newSize - the new width of the character and attributes rows
|
||||
// Return Value:
|
||||
// - S_OK on success, otherwise relevant error code
|
||||
[[nodiscard]] HRESULT CharRow::Resize(const til::CoordType newSize) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
const value_type insertVals;
|
||||
_data.resize(newSize, insertVals);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
typename CharRow::iterator CharRow::begin() noexcept
|
||||
{
|
||||
return _data.begin();
|
||||
}
|
||||
|
||||
typename CharRow::const_iterator CharRow::cbegin() const noexcept
|
||||
{
|
||||
return _data.cbegin();
|
||||
}
|
||||
|
||||
typename CharRow::iterator CharRow::end() noexcept
|
||||
{
|
||||
return _data.end();
|
||||
}
|
||||
|
||||
typename CharRow::const_iterator CharRow::cend() const noexcept
|
||||
{
|
||||
return _data.cend();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Inspects the current internal string to find the left edge of it
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The calculated left boundary of the internal string.
|
||||
til::CoordType CharRow::MeasureLeft() const noexcept
|
||||
{
|
||||
auto it = _data.cbegin();
|
||||
while (it != _data.cend() && it->IsSpace())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
return gsl::narrow_cast<til::CoordType>(it - _data.cbegin());
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Inspects the current internal string to find the right edge of it
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The calculated right boundary of the internal string.
|
||||
til::CoordType CharRow::MeasureRight() const
|
||||
{
|
||||
auto it = _data.crbegin();
|
||||
while (it != _data.crend() && it->IsSpace())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
return gsl::narrow_cast<til::CoordType>(_data.crend() - it);
|
||||
}
|
||||
|
||||
void CharRow::ClearCell(const til::CoordType column)
|
||||
{
|
||||
_data.at(column).Reset();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Tells you whether or not this row contains any valid text.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - True if there is valid text in this row. False otherwise.
|
||||
bool CharRow::ContainsText() const noexcept
|
||||
{
|
||||
for (const auto& cell : _data)
|
||||
{
|
||||
if (!cell.IsSpace())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - gets the attribute at the specified column
|
||||
// Arguments:
|
||||
// - column - the column to get the attribute for
|
||||
// Return Value:
|
||||
// - the attribute
|
||||
// Note: will throw exception if column is out of bounds
|
||||
const DbcsAttribute& CharRow::DbcsAttrAt(const til::CoordType column) const
|
||||
{
|
||||
return _data.at(column).DbcsAttr();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - gets the attribute at the specified column
|
||||
// Arguments:
|
||||
// - column - the column to get the attribute for
|
||||
// Return Value:
|
||||
// - the attribute
|
||||
// Note: will throw exception if column is out of bounds
|
||||
DbcsAttribute& CharRow::DbcsAttrAt(const til::CoordType column)
|
||||
{
|
||||
return _data.at(column).DbcsAttr();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - resets text data at column
|
||||
// Arguments:
|
||||
// - column - column index to clear text data from
|
||||
// Return Value:
|
||||
// - <none>
|
||||
// Note: will throw exception if column is out of bounds
|
||||
void CharRow::ClearGlyph(const til::CoordType column)
|
||||
{
|
||||
_data.at(column).EraseChars();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - returns text data at column as a const reference.
|
||||
// Arguments:
|
||||
// - column - column to get text data for
|
||||
// Return Value:
|
||||
// - text data at column
|
||||
// - Note: will throw exception if column is out of bounds
|
||||
const CharRow::reference CharRow::GlyphAt(const til::CoordType column) const
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, column < 0 || column >= gsl::narrow_cast<til::CoordType>(_data.size()));
|
||||
return { const_cast<CharRow&>(*this), column };
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - returns text data at column as a reference.
|
||||
// Arguments:
|
||||
// - column - column to get text data for
|
||||
// Return Value:
|
||||
// - text data at column
|
||||
// - Note: will throw exception if column is out of bounds
|
||||
CharRow::reference CharRow::GlyphAt(const til::CoordType column)
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, column < 0 || column >= gsl::narrow_cast<til::CoordType>(_data.size()));
|
||||
return { *this, column };
|
||||
}
|
||||
|
||||
std::wstring CharRow::GetText() const
|
||||
{
|
||||
std::wstring wstr;
|
||||
wstr.reserve(_data.size());
|
||||
|
||||
for (til::CoordType i = 0; i < gsl::narrow_cast<til::CoordType>(_data.size()); ++i)
|
||||
{
|
||||
const auto glyph = GlyphAt(i);
|
||||
if (!DbcsAttrAt(i).IsTrailing())
|
||||
{
|
||||
for (const auto wch : glyph)
|
||||
{
|
||||
wstr.push_back(wch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return wstr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - get delimiter class for a position in the char row
|
||||
// - used for double click selection and uia word navigation
|
||||
// Arguments:
|
||||
// - column: column to get text data for
|
||||
// - wordDelimiters: the delimiters defined as a part of the DelimiterClass::DelimiterChar
|
||||
// Return Value:
|
||||
// - the delimiter class for the given char
|
||||
const DelimiterClass CharRow::DelimiterClassAt(const til::CoordType column, const std::wstring_view wordDelimiters) const
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, column < 0 || column >= gsl::narrow_cast<til::CoordType>(_data.size()));
|
||||
|
||||
const auto glyph = *GlyphAt(column).begin();
|
||||
if (glyph <= UNICODE_SPACE)
|
||||
{
|
||||
return DelimiterClass::ControlChar;
|
||||
}
|
||||
else if (wordDelimiters.find(glyph) != std::wstring_view::npos)
|
||||
{
|
||||
return DelimiterClass::DelimiterChar;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DelimiterClass::RegularChar;
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeStorage& CharRow::GetUnicodeStorage() noexcept
|
||||
{
|
||||
return _pParent->GetUnicodeStorage();
|
||||
}
|
||||
|
||||
const UnicodeStorage& CharRow::GetUnicodeStorage() const noexcept
|
||||
{
|
||||
return _pParent->GetUnicodeStorage();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - calculates the key used by the given column of the char row to store glyph data in UnicodeStorage
|
||||
// Arguments:
|
||||
// - column - the column to generate the key for
|
||||
// Return Value:
|
||||
// - the til::point key for data access from UnicodeStorage for the column
|
||||
til::point CharRow::GetStorageKey(const til::CoordType column) const noexcept
|
||||
{
|
||||
return { column, _pParent->GetId() };
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Updates the pointer to the parent row (which might change if we shuffle the rows around)
|
||||
// Arguments:
|
||||
// - pParent - Pointer to the parent row
|
||||
void CharRow::UpdateParent(ROW* const pParent)
|
||||
{
|
||||
_pParent = FAIL_FAST_IF_NULL(pParent);
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- CharRow.hpp
|
||||
|
||||
Abstract:
|
||||
- contains data structure for UCS2 encoded character data of a row
|
||||
|
||||
Author(s):
|
||||
- Michael Niksa (miniksa) 10-Apr-2014
|
||||
- Paul Campbell (paulcam) 10-Apr-2014
|
||||
|
||||
Revision History:
|
||||
- From components of output.h/.c
|
||||
by Therese Stowell (ThereseS) 1990-1991
|
||||
- Pulled into its own file from textBuffer.hpp/cpp (AustDi, 2017)
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <til/small_vector.h>
|
||||
|
||||
#include "DbcsAttribute.hpp"
|
||||
#include "CharRowCellReference.hpp"
|
||||
#include "CharRowCell.hpp"
|
||||
#include "UnicodeStorage.hpp"
|
||||
|
||||
class ROW;
|
||||
|
||||
enum class DelimiterClass
|
||||
{
|
||||
ControlChar,
|
||||
DelimiterChar,
|
||||
RegularChar
|
||||
};
|
||||
|
||||
// the characters of one row of screen buffer
|
||||
// we keep the following values so that we don't write
|
||||
// more pixels to the screen than we have to:
|
||||
// left is initialized to screenbuffer width. right is
|
||||
// initialized to zero.
|
||||
//
|
||||
// [ foo.bar 12-12-61 ]
|
||||
// ^ ^ ^ ^
|
||||
// | | | |
|
||||
// Chars Left Right end of Chars buffer
|
||||
class CharRow final
|
||||
{
|
||||
public:
|
||||
using glyph_type = wchar_t;
|
||||
using value_type = CharRowCell;
|
||||
using iterator = til::small_vector<value_type, 120>::iterator;
|
||||
using const_iterator = til::small_vector<value_type, 120>::const_iterator;
|
||||
using const_reverse_iterator = til::small_vector<value_type, 120>::const_reverse_iterator;
|
||||
using reference = CharRowCellReference;
|
||||
|
||||
CharRow(til::CoordType rowWidth, ROW* const pParent) noexcept;
|
||||
|
||||
til::CoordType size() const noexcept;
|
||||
[[nodiscard]] HRESULT Resize(const til::CoordType newSize) noexcept;
|
||||
til::CoordType MeasureLeft() const noexcept;
|
||||
til::CoordType MeasureRight() const;
|
||||
bool ContainsText() const noexcept;
|
||||
const DbcsAttribute& DbcsAttrAt(const til::CoordType column) const;
|
||||
DbcsAttribute& DbcsAttrAt(const til::CoordType column);
|
||||
void ClearGlyph(const til::CoordType column);
|
||||
|
||||
const DelimiterClass DelimiterClassAt(const til::CoordType column, const std::wstring_view wordDelimiters) const;
|
||||
|
||||
// working with glyphs
|
||||
const reference GlyphAt(const til::CoordType column) const;
|
||||
reference GlyphAt(const til::CoordType column);
|
||||
|
||||
// iterators
|
||||
iterator begin() noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
const_iterator begin() const noexcept { return cbegin(); }
|
||||
|
||||
iterator end() noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
const_iterator end() const noexcept { return cend(); }
|
||||
|
||||
UnicodeStorage& GetUnicodeStorage() noexcept;
|
||||
const UnicodeStorage& GetUnicodeStorage() const noexcept;
|
||||
til::point GetStorageKey(const til::CoordType column) const noexcept;
|
||||
|
||||
void UpdateParent(ROW* const pParent);
|
||||
|
||||
friend CharRowCellReference;
|
||||
friend class ROW;
|
||||
|
||||
private:
|
||||
void Reset() noexcept;
|
||||
void ClearCell(const til::CoordType column);
|
||||
std::wstring GetText() const;
|
||||
|
||||
protected:
|
||||
// storage for glyph data and dbcs attributes
|
||||
til::small_vector<value_type, 120> _data;
|
||||
|
||||
// ROW that this CharRow belongs to
|
||||
ROW* _pParent;
|
||||
};
|
||||
|
||||
template<typename InputIt1, typename InputIt2>
|
||||
void OverwriteColumns(InputIt1 startChars, InputIt1 endChars, InputIt2 startAttrs, CharRow::iterator outIt)
|
||||
{
|
||||
std::transform(startChars,
|
||||
endChars,
|
||||
startAttrs,
|
||||
outIt,
|
||||
[](const wchar_t wch, const DbcsAttribute attr) {
|
||||
return CharRow::value_type{ wch, attr };
|
||||
});
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#include "precomp.h"
|
||||
|
||||
#include "CharRowCell.hpp"
|
||||
#include "unicode.hpp"
|
||||
|
||||
// default glyph value, used for resetting the character data portion of a cell
|
||||
static constexpr wchar_t DefaultValue = UNICODE_SPACE;
|
||||
|
||||
// Routine Description:
|
||||
// - "erases" the glyph. really sets it back to the default "empty" value
|
||||
void CharRowCell::EraseChars() noexcept
|
||||
{
|
||||
if (_attr.IsGlyphStored())
|
||||
{
|
||||
_attr.SetGlyphStored(false);
|
||||
}
|
||||
_wch = DefaultValue;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - resets this object back to the defaults it would have from the default constructor
|
||||
void CharRowCell::Reset() noexcept
|
||||
{
|
||||
_attr.Reset();
|
||||
_wch = DefaultValue;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - checks if cell contains a space glyph
|
||||
// Return Value:
|
||||
// - true if cell contains a space glyph, false otherwise
|
||||
bool CharRowCell::IsSpace() const noexcept
|
||||
{
|
||||
return !_attr.IsGlyphStored() && _wch == UNICODE_SPACE;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Access the DbcsAttribute for the cell
|
||||
// Return Value:
|
||||
// - ref to the cells' DbcsAttribute
|
||||
DbcsAttribute& CharRowCell::DbcsAttr() noexcept
|
||||
{
|
||||
return _attr;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Access the DbcsAttribute for the cell
|
||||
// Return Value:
|
||||
// - ref to the cells' DbcsAttribute
|
||||
const DbcsAttribute& CharRowCell::DbcsAttr() const noexcept
|
||||
{
|
||||
return _attr;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Access the cell's wchar field. this does not access any char data through UnicodeStorage.
|
||||
// Return Value:
|
||||
// - the cell's wchar field
|
||||
wchar_t& CharRowCell::Char() noexcept
|
||||
{
|
||||
return _wch;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Access the cell's wchar field. this does not access any char data through UnicodeStorage.
|
||||
// Return Value:
|
||||
// - the cell's wchar field
|
||||
const wchar_t& CharRowCell::Char() const noexcept
|
||||
{
|
||||
return _wch;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- CharRowCell.hpp
|
||||
|
||||
Abstract:
|
||||
- data structure for one cell of a char row. contains the char data for one
|
||||
coordinate position in the output buffer (leading/trailing information and
|
||||
the char itself.
|
||||
|
||||
Author(s):
|
||||
- Austin Diviness (AustDi) 02-May-2018
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DbcsAttribute.hpp"
|
||||
#include "unicode.hpp"
|
||||
|
||||
#if (defined(_M_IX86) || defined(_M_AMD64))
|
||||
// currently CharRowCell's fields use 3 bytes of memory, leaving the 4th byte in unused. this leads
|
||||
// to a rather large amount of useless memory allocated. so instead, pack CharRowCell by bytes instead of words.
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
class CharRowCell final
|
||||
{
|
||||
public:
|
||||
CharRowCell() noexcept = default;
|
||||
CharRowCell(const wchar_t wch, const DbcsAttribute attr) noexcept
|
||||
:
|
||||
_wch(wch),
|
||||
_attr(attr)
|
||||
{
|
||||
}
|
||||
|
||||
void EraseChars() noexcept;
|
||||
void Reset() noexcept;
|
||||
|
||||
bool IsSpace() const noexcept;
|
||||
|
||||
DbcsAttribute& DbcsAttr() noexcept;
|
||||
const DbcsAttribute& DbcsAttr() const noexcept;
|
||||
|
||||
wchar_t& Char() noexcept;
|
||||
const wchar_t& Char() const noexcept;
|
||||
|
||||
friend constexpr bool operator==(const CharRowCell& a, const CharRowCell& b) noexcept;
|
||||
|
||||
private:
|
||||
wchar_t _wch{ UNICODE_SPACE };
|
||||
DbcsAttribute _attr{};
|
||||
};
|
||||
|
||||
#if (defined(_M_IX86) || defined(_M_AMD64))
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
constexpr bool operator==(const CharRowCell& a, const CharRowCell& b) noexcept
|
||||
{
|
||||
return (a._wch == b._wch &&
|
||||
a._attr == b._attr);
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "UnicodeStorage.hpp"
|
||||
#include "CharRow.hpp"
|
||||
|
||||
// Routine Description:
|
||||
// - assignment operator. will store extended glyph data in a separate storage location
|
||||
// Arguments:
|
||||
// - chars - the glyph data to store
|
||||
void CharRowCellReference::operator=(const std::wstring_view chars)
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, chars.empty());
|
||||
if (chars.size() == 1)
|
||||
{
|
||||
_cellData().Char() = chars.front();
|
||||
_cellData().DbcsAttr().SetGlyphStored(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& storage = _parent.GetUnicodeStorage();
|
||||
const auto key = _parent.GetStorageKey(_index);
|
||||
storage.StoreGlyph(key, { chars.cbegin(), chars.cend() });
|
||||
_cellData().DbcsAttr().SetGlyphStored(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - implicit conversion to vector<wchar_t> operator.
|
||||
// Return Value:
|
||||
// - std::vector<wchar_t> of the glyph data in the referenced cell
|
||||
CharRowCellReference::operator std::wstring_view() const
|
||||
{
|
||||
return _glyphData();
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - The CharRowCell this object "references"
|
||||
// Return Value:
|
||||
// - ref to the CharRowCell
|
||||
CharRowCell& CharRowCellReference::_cellData()
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - The CharRowCell this object "references"
|
||||
// Return Value:
|
||||
// - ref to the CharRowCell
|
||||
const CharRowCell& CharRowCellReference::_cellData() const
|
||||
{
|
||||
return _parent._data.at(_index);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - the glyph data of the referenced cell
|
||||
// Return Value:
|
||||
// - the glyph data
|
||||
std::wstring_view CharRowCellReference::_glyphData() const
|
||||
{
|
||||
if (_cellData().DbcsAttr().IsGlyphStored())
|
||||
{
|
||||
const auto& text = _parent.GetUnicodeStorage().GetText(_parent.GetStorageKey(_index));
|
||||
|
||||
return { text.data(), text.size() };
|
||||
}
|
||||
else
|
||||
{
|
||||
return { &_cellData().Char(), 1 };
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - gets read-only iterator to the beginning of the glyph data
|
||||
// Return Value:
|
||||
// - iterator of the glyph data
|
||||
CharRowCellReference::const_iterator CharRowCellReference::begin() const
|
||||
{
|
||||
if (_cellData().DbcsAttr().IsGlyphStored())
|
||||
{
|
||||
return _parent.GetUnicodeStorage().GetText(_parent.GetStorageKey(_index)).data();
|
||||
}
|
||||
else
|
||||
{
|
||||
return &_cellData().Char();
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - get read-only iterator to the end of the glyph data
|
||||
// Return Value:
|
||||
// - end iterator of the glyph data
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26481)
|
||||
// TODO GH 2672: eliminate using pointers raw as begin/end markers in this class
|
||||
CharRowCellReference::const_iterator CharRowCellReference::end() const
|
||||
{
|
||||
if (_cellData().DbcsAttr().IsGlyphStored())
|
||||
{
|
||||
const auto& chars = _parent.GetUnicodeStorage().GetText(_parent.GetStorageKey(_index));
|
||||
return chars.data() + chars.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
return &_cellData().Char() + 1;
|
||||
}
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
bool operator==(const CharRowCellReference& ref, const std::vector<wchar_t>& glyph)
|
||||
{
|
||||
const auto& dbcsAttr = ref._cellData().DbcsAttr();
|
||||
if (glyph.size() == 1 && dbcsAttr.IsGlyphStored())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (glyph.size() > 1 && !dbcsAttr.IsGlyphStored())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (glyph.size() == 1 && !dbcsAttr.IsGlyphStored())
|
||||
{
|
||||
return ref._cellData().Char() == glyph.front();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& chars = ref._parent.GetUnicodeStorage().GetText(ref._parent.GetStorageKey(ref._index));
|
||||
return chars == glyph;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const std::vector<wchar_t>& glyph, const CharRowCellReference& ref)
|
||||
{
|
||||
return ref == glyph;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- CharRowCellReference.hpp
|
||||
|
||||
Abstract:
|
||||
- reference class for the glyph data of a char row cell
|
||||
|
||||
Author(s):
|
||||
- Austin Diviness (AustDi) 02-May-2018
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DbcsAttribute.hpp"
|
||||
#include "CharRowCell.hpp"
|
||||
#include <utility>
|
||||
|
||||
class CharRow;
|
||||
|
||||
class CharRowCellReference final
|
||||
{
|
||||
public:
|
||||
using const_iterator = const wchar_t*;
|
||||
|
||||
CharRowCellReference(CharRow& parent, const til::CoordType index) noexcept :
|
||||
_parent{ parent },
|
||||
_index{ index }
|
||||
{
|
||||
}
|
||||
|
||||
~CharRowCellReference() = default;
|
||||
CharRowCellReference(const CharRowCellReference&) noexcept = default;
|
||||
CharRowCellReference(CharRowCellReference&&) noexcept = default;
|
||||
|
||||
void operator=(const CharRowCellReference&) = delete;
|
||||
void operator=(CharRowCellReference&&) = delete;
|
||||
|
||||
void operator=(const std::wstring_view chars);
|
||||
operator std::wstring_view() const;
|
||||
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
|
||||
friend bool operator==(const CharRowCellReference& ref, const std::vector<wchar_t>& glyph);
|
||||
friend bool operator==(const std::vector<wchar_t>& glyph, const CharRowCellReference& ref);
|
||||
|
||||
private:
|
||||
// what char row the object belongs to
|
||||
CharRow& _parent;
|
||||
// the index of the cell in the parent char row
|
||||
til::CoordType _index;
|
||||
|
||||
CharRowCell& _cellData();
|
||||
const CharRowCell& _cellData() const;
|
||||
|
||||
std::wstring_view _glyphData() const;
|
||||
};
|
||||
|
||||
bool operator==(const CharRowCellReference& ref, const std::vector<wchar_t>& glyph);
|
||||
bool operator==(const std::vector<wchar_t>& glyph, const CharRowCellReference& ref);
|
||||
@@ -16,129 +16,22 @@ Revision History:
|
||||
|
||||
#pragma once
|
||||
|
||||
class DbcsAttribute final
|
||||
enum class DbcsAttribute : uint8_t
|
||||
{
|
||||
public:
|
||||
enum class Attribute : BYTE
|
||||
{
|
||||
Single = 0x00,
|
||||
Leading = 0x01,
|
||||
Trailing = 0x02
|
||||
};
|
||||
|
||||
DbcsAttribute() noexcept :
|
||||
_attribute{ Attribute::Single },
|
||||
_glyphStored{ false }
|
||||
{
|
||||
}
|
||||
|
||||
DbcsAttribute(const Attribute attribute) noexcept :
|
||||
_attribute{ attribute },
|
||||
_glyphStored{ false }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool IsSingle() const noexcept
|
||||
{
|
||||
return _attribute == Attribute::Single;
|
||||
}
|
||||
|
||||
constexpr bool IsLeading() const noexcept
|
||||
{
|
||||
return _attribute == Attribute::Leading;
|
||||
}
|
||||
|
||||
constexpr bool IsTrailing() const noexcept
|
||||
{
|
||||
return _attribute == Attribute::Trailing;
|
||||
}
|
||||
|
||||
constexpr bool IsDbcs() const noexcept
|
||||
{
|
||||
return IsLeading() || IsTrailing();
|
||||
}
|
||||
|
||||
constexpr bool IsGlyphStored() const noexcept
|
||||
{
|
||||
return _glyphStored;
|
||||
}
|
||||
|
||||
void SetGlyphStored(const bool stored) noexcept
|
||||
{
|
||||
_glyphStored = stored;
|
||||
}
|
||||
|
||||
void SetSingle() noexcept
|
||||
{
|
||||
_attribute = Attribute::Single;
|
||||
}
|
||||
|
||||
void SetLeading() noexcept
|
||||
{
|
||||
_attribute = Attribute::Leading;
|
||||
}
|
||||
|
||||
void SetTrailing() noexcept
|
||||
{
|
||||
_attribute = Attribute::Trailing;
|
||||
}
|
||||
|
||||
void Reset() noexcept
|
||||
{
|
||||
SetSingle();
|
||||
SetGlyphStored(false);
|
||||
}
|
||||
|
||||
WORD GeneratePublicApiAttributeFormat() const noexcept
|
||||
{
|
||||
WORD publicAttribute = 0;
|
||||
if (IsLeading())
|
||||
{
|
||||
WI_SetFlag(publicAttribute, COMMON_LVB_LEADING_BYTE);
|
||||
}
|
||||
if (IsTrailing())
|
||||
{
|
||||
WI_SetFlag(publicAttribute, COMMON_LVB_TRAILING_BYTE);
|
||||
}
|
||||
return publicAttribute;
|
||||
}
|
||||
|
||||
static DbcsAttribute FromPublicApiAttributeFormat(WORD publicAttribute)
|
||||
{
|
||||
// it's not valid to be both a leading and trailing byte
|
||||
if (WI_AreAllFlagsSet(publicAttribute, COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE))
|
||||
{
|
||||
THROW_HR(E_INVALIDARG);
|
||||
}
|
||||
|
||||
DbcsAttribute attr;
|
||||
if (WI_IsFlagSet(publicAttribute, COMMON_LVB_LEADING_BYTE))
|
||||
{
|
||||
attr.SetLeading();
|
||||
}
|
||||
else if (WI_IsFlagSet(publicAttribute, COMMON_LVB_TRAILING_BYTE))
|
||||
{
|
||||
attr.SetTrailing();
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(const DbcsAttribute& a, const DbcsAttribute& b) noexcept;
|
||||
|
||||
private:
|
||||
Attribute _attribute : 2;
|
||||
bool _glyphStored : 1;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TextBufferTests;
|
||||
#endif
|
||||
Single,
|
||||
Leading,
|
||||
Trailing,
|
||||
};
|
||||
|
||||
constexpr bool operator==(const DbcsAttribute& a, const DbcsAttribute& b) noexcept
|
||||
constexpr WORD GeneratePublicApiAttributeFormat(DbcsAttribute attribute) noexcept
|
||||
{
|
||||
return a._attribute == b._attribute;
|
||||
switch (attribute)
|
||||
{
|
||||
case DbcsAttribute::Leading:
|
||||
return COMMON_LVB_LEADING_BYTE;
|
||||
case DbcsAttribute::Trailing:
|
||||
return COMMON_LVB_TRAILING_BYTE;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(sizeof(DbcsAttribute) == sizeof(BYTE), "DbcsAttribute should be one byte big. if this changes then it needs "
|
||||
"either an implicit conversion to a BYTE or an update to all places "
|
||||
"that assume it's a byte big");
|
||||
|
||||
@@ -13,7 +13,7 @@ Abstract:
|
||||
|
||||
#pragma once
|
||||
|
||||
enum class LineRendition
|
||||
enum class LineRendition : uint8_t
|
||||
{
|
||||
SingleWidth,
|
||||
DoubleWidth,
|
||||
|
||||
@@ -80,7 +80,7 @@ private:
|
||||
// basic_string contains a small storage internally so we don't need
|
||||
// to worry about heap allocation for short strings.
|
||||
std::wstring _text;
|
||||
DbcsAttribute _dbcsAttribute;
|
||||
DbcsAttribute _dbcsAttribute = DbcsAttribute::Single;
|
||||
TextAttribute _textAttribute;
|
||||
TextAttributeBehavior _behavior;
|
||||
|
||||
|
||||
@@ -240,13 +240,10 @@ OutputCellIterator& OutputCellIterator::operator++()
|
||||
{
|
||||
if (!_TryMoveTrailing())
|
||||
{
|
||||
if (_currentView.DbcsAttr().IsTrailing())
|
||||
if (_currentView.DbcsAttr() == DbcsAttribute::Trailing)
|
||||
{
|
||||
auto dbcsAttr = _currentView.DbcsAttr();
|
||||
dbcsAttr.SetLeading();
|
||||
|
||||
_currentView = OutputCellView(_currentView.Chars(),
|
||||
dbcsAttr,
|
||||
DbcsAttribute::Leading,
|
||||
_currentView.TextAttr(),
|
||||
_currentView.TextAttrBehavior());
|
||||
}
|
||||
@@ -336,13 +333,10 @@ const OutputCellView* OutputCellIterator::operator->() const noexcept
|
||||
// - False if this wasn't applicable and the caller should update the view.
|
||||
bool OutputCellIterator::_TryMoveTrailing() noexcept
|
||||
{
|
||||
if (_currentView.DbcsAttr().IsLeading())
|
||||
if (_currentView.DbcsAttr() == DbcsAttribute::Leading)
|
||||
{
|
||||
auto dbcsAttr = _currentView.DbcsAttr();
|
||||
dbcsAttr.SetTrailing();
|
||||
|
||||
_currentView = OutputCellView(_currentView.Chars(),
|
||||
dbcsAttr,
|
||||
DbcsAttribute::Trailing,
|
||||
_currentView.TextAttr(),
|
||||
_currentView.TextAttrBehavior());
|
||||
return true;
|
||||
@@ -399,12 +393,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view,
|
||||
const TextAttributeBehavior behavior)
|
||||
{
|
||||
const auto glyph = Utf16Parser::ParseNext(view);
|
||||
DbcsAttribute dbcsAttr;
|
||||
if (IsGlyphFullWidth(glyph))
|
||||
{
|
||||
dbcsAttr.SetLeading();
|
||||
}
|
||||
|
||||
const auto dbcsAttr = IsGlyphFullWidth(glyph) ? DbcsAttribute::Leading : DbcsAttribute::Single;
|
||||
return OutputCellView(glyph, dbcsAttr, attr, behavior);
|
||||
}
|
||||
|
||||
@@ -420,13 +409,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view,
|
||||
OutputCellView OutputCellIterator::s_GenerateView(const wchar_t& wch) noexcept
|
||||
{
|
||||
const auto glyph = std::wstring_view(&wch, 1);
|
||||
|
||||
DbcsAttribute dbcsAttr;
|
||||
if (IsGlyphFullWidth(wch))
|
||||
{
|
||||
dbcsAttr.SetLeading();
|
||||
}
|
||||
|
||||
const auto dbcsAttr = IsGlyphFullWidth(wch) ? DbcsAttribute::Leading : DbcsAttribute::Single;
|
||||
return OutputCellView(glyph, dbcsAttr, InvalidTextAttribute, TextAttributeBehavior::Current);
|
||||
}
|
||||
|
||||
@@ -457,13 +440,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const TextAttribute& attr) noe
|
||||
OutputCellView OutputCellIterator::s_GenerateView(const wchar_t& wch, const TextAttribute& attr) noexcept
|
||||
{
|
||||
const auto glyph = std::wstring_view(&wch, 1);
|
||||
|
||||
DbcsAttribute dbcsAttr;
|
||||
if (IsGlyphFullWidth(wch))
|
||||
{
|
||||
dbcsAttr.SetLeading();
|
||||
}
|
||||
|
||||
const auto dbcsAttr = IsGlyphFullWidth(wch) ? DbcsAttribute::Leading : DbcsAttribute::Single;
|
||||
return OutputCellView(glyph, dbcsAttr, attr, TextAttributeBehavior::Stored);
|
||||
}
|
||||
|
||||
@@ -498,14 +475,14 @@ OutputCellView OutputCellIterator::s_GenerateView(const CHAR_INFO& charInfo) noe
|
||||
{
|
||||
const auto glyph = std::wstring_view(&charInfo.Char.UnicodeChar, 1);
|
||||
|
||||
DbcsAttribute dbcsAttr;
|
||||
DbcsAttribute dbcsAttr = DbcsAttribute::Single;
|
||||
if (WI_IsFlagSet(charInfo.Attributes, COMMON_LVB_LEADING_BYTE))
|
||||
{
|
||||
dbcsAttr.SetLeading();
|
||||
dbcsAttr = DbcsAttribute::Leading;
|
||||
}
|
||||
else if (WI_IsFlagSet(charInfo.Attributes, COMMON_LVB_TRAILING_BYTE))
|
||||
{
|
||||
dbcsAttr.SetTrailing();
|
||||
dbcsAttr = DbcsAttribute::Trailing;
|
||||
}
|
||||
|
||||
const TextAttribute textAttr(charInfo.Attributes);
|
||||
|
||||
@@ -40,20 +40,7 @@ OutputCellView::OutputCellView(const std::wstring_view view,
|
||||
// - Count of column cells on the screen
|
||||
til::CoordType OutputCellView::Columns() const noexcept
|
||||
{
|
||||
if (DbcsAttr().IsSingle())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (DbcsAttr().IsLeading())
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if (DbcsAttr().IsTrailing())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return DbcsAttr() == DbcsAttribute::Leading ? 2 : 1;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
|
||||
private:
|
||||
std::wstring_view _view;
|
||||
DbcsAttribute _dbcsAttr;
|
||||
DbcsAttribute _dbcsAttr = DbcsAttribute::Single;
|
||||
TextAttribute _textAttr;
|
||||
TextAttributeBehavior _behavior;
|
||||
};
|
||||
|
||||
@@ -3,29 +3,129 @@
|
||||
|
||||
#include "precomp.h"
|
||||
#include "Row.hpp"
|
||||
#include "CharRow.hpp"
|
||||
|
||||
#include "textBuffer.hpp"
|
||||
#include "../types/inc/convert.hpp"
|
||||
|
||||
// The STL is missing a std::iota_n analogue for std::iota, so I made my own.
|
||||
template<typename OutIt, typename Diff, typename T>
|
||||
constexpr OutIt iota_n(OutIt dest, Diff count, T val)
|
||||
{
|
||||
for (; count; --count, ++dest, ++val)
|
||||
{
|
||||
*dest = val;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
// ROW::ReplaceCharacters needs to calculate `val + count` after
|
||||
// calling iota_n() and this function achieves both things at once.
|
||||
template<typename OutIt, typename Diff, typename T>
|
||||
constexpr OutIt iota_n_mut(OutIt dest, Diff count, T& val)
|
||||
{
|
||||
for (; count; --count, ++dest, ++val)
|
||||
{
|
||||
*dest = val;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Same as std::fill, but purpose-built for very small `last - first`
|
||||
// where a trivial loop outperforms vectorization.
|
||||
template<typename FwdIt, typename T>
|
||||
constexpr FwdIt fill_small(FwdIt first, FwdIt last, const T val)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
*first = val;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
// Same as std::fill_n, but purpose-built for very small `count`
|
||||
// where a trivial loop outperforms vectorization.
|
||||
template<typename OutIt, typename Diff, typename T>
|
||||
constexpr OutIt fill_n_small(OutIt dest, Diff count, const T val)
|
||||
{
|
||||
for (; count; --count, ++dest)
|
||||
{
|
||||
*dest = val;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Same as std::copy_n, but purpose-built for very short `count`
|
||||
// where a trivial loop outperforms vectorization.
|
||||
template<typename InIt, typename Diff, typename OutIt>
|
||||
constexpr OutIt copy_n_small(InIt first, Diff count, OutIt dest)
|
||||
{
|
||||
for (; count; --count, ++dest, ++first)
|
||||
{
|
||||
*dest = *first;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - constructor
|
||||
// Arguments:
|
||||
// - rowId - the row index in the text buffer
|
||||
// - rowWidth - the width of the row, cell elements
|
||||
// - fillAttribute - the default text attribute
|
||||
// - pParent - the text buffer that this row belongs to
|
||||
// Return Value:
|
||||
// - constructed object
|
||||
ROW::ROW(const til::CoordType rowId, const til::CoordType rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent) :
|
||||
_id{ rowId },
|
||||
_rowWidth{ rowWidth },
|
||||
_charRow{ rowWidth, this },
|
||||
_attrRow{ rowWidth, fillAttribute },
|
||||
_lineRendition{ LineRendition::SingleWidth },
|
||||
_wrapForced{ false },
|
||||
_doubleBytePadded{ false },
|
||||
_pParent{ pParent }
|
||||
ROW::ROW(wchar_t* charsBuffer, uint16_t* charOffsetsBuffer, uint16_t rowWidth, const TextAttribute& fillAttribute) :
|
||||
_charsBuffer{ charsBuffer },
|
||||
_chars{ charsBuffer, rowWidth },
|
||||
_charOffsets{ charOffsetsBuffer, ::base::strict_cast<size_t>(rowWidth) + 1u },
|
||||
_attr{ rowWidth, fillAttribute },
|
||||
_columnCount{ rowWidth }
|
||||
{
|
||||
if (_chars.data())
|
||||
{
|
||||
_init();
|
||||
}
|
||||
}
|
||||
|
||||
void swap(ROW& lhs, ROW& rhs) noexcept
|
||||
{
|
||||
std::swap(lhs._charsBuffer, rhs._charsBuffer);
|
||||
std::swap(lhs._charsHeap, rhs._charsHeap);
|
||||
std::swap(lhs._chars, rhs._chars);
|
||||
std::swap(lhs._charOffsets, rhs._charOffsets);
|
||||
std::swap(lhs._attr, rhs._attr);
|
||||
std::swap(lhs._columnCount, rhs._columnCount);
|
||||
std::swap(lhs._lineRendition, rhs._lineRendition);
|
||||
std::swap(lhs._wrapForced, rhs._wrapForced);
|
||||
std::swap(lhs._doubleBytePadded, rhs._doubleBytePadded);
|
||||
}
|
||||
|
||||
void ROW::SetWrapForced(const bool wrap) noexcept
|
||||
{
|
||||
_wrapForced = wrap;
|
||||
}
|
||||
|
||||
bool ROW::WasWrapForced() const noexcept
|
||||
{
|
||||
return _wrapForced;
|
||||
}
|
||||
|
||||
void ROW::SetDoubleBytePadded(const bool doubleBytePadded) noexcept
|
||||
{
|
||||
_doubleBytePadded = doubleBytePadded;
|
||||
}
|
||||
|
||||
bool ROW::WasDoubleBytePadded() const noexcept
|
||||
{
|
||||
return _doubleBytePadded;
|
||||
}
|
||||
|
||||
void ROW::SetLineRendition(const LineRendition lineRendition) noexcept
|
||||
{
|
||||
_lineRendition = lineRendition;
|
||||
}
|
||||
|
||||
LineRendition ROW::GetLineRendition() const noexcept
|
||||
{
|
||||
return _lineRendition;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -34,42 +134,99 @@ ROW::ROW(const til::CoordType rowId, const til::CoordType rowWidth, const TextAt
|
||||
// - Attr - The default attribute (color) to fill
|
||||
// Return Value:
|
||||
// - <none>
|
||||
bool ROW::Reset(const TextAttribute Attr)
|
||||
void ROW::Reset(const TextAttribute& attr)
|
||||
{
|
||||
_charsHeap.reset();
|
||||
_chars = { _charsBuffer, _columnCount };
|
||||
_attr = { _columnCount, attr };
|
||||
_lineRendition = LineRendition::SingleWidth;
|
||||
_wrapForced = false;
|
||||
_doubleBytePadded = false;
|
||||
_charRow.Reset();
|
||||
try
|
||||
{
|
||||
_attrRow.Reset(Attr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
_init();
|
||||
}
|
||||
|
||||
void ROW::_init() noexcept
|
||||
{
|
||||
std::fill_n(_chars.begin(), _columnCount, UNICODE_SPACE);
|
||||
std::iota(_charOffsets.begin(), _charOffsets.end(), uint16_t{ 0 });
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - resizes ROW to new width
|
||||
// Arguments:
|
||||
// - width - the new width, in cells
|
||||
// Return Value:
|
||||
// - S_OK if successful, otherwise relevant error
|
||||
[[nodiscard]] HRESULT ROW::Resize(const til::CoordType width)
|
||||
// - charsBuffer - a new backing buffer to use for _charsBuffer
|
||||
// - charOffsetsBuffer - a new backing buffer to use for _charOffsets
|
||||
// - rowWidth - the new width, in cells
|
||||
// - fillAttribute - the attribute to use for any newly added, trailing cells
|
||||
void ROW::Resize(wchar_t* charsBuffer, uint16_t* charOffsetsBuffer, uint16_t rowWidth, const TextAttribute& fillAttribute)
|
||||
{
|
||||
RETURN_IF_FAILED(_charRow.Resize(width));
|
||||
try
|
||||
// A default-constructed ROW has no cols/chars to copy.
|
||||
// It can be detected by the lack of a _charsBuffer (among others).
|
||||
//
|
||||
// Otherwise, this block figures out how much we can copy into the new `rowWidth`.
|
||||
uint16_t colsToCopy = 0;
|
||||
uint16_t charsToCopy = 0;
|
||||
if (_charsBuffer)
|
||||
{
|
||||
_attrRow.Resize(width);
|
||||
colsToCopy = std::min(rowWidth, _columnCount);
|
||||
// Safety: colsToCopy is [0, _columnCount].
|
||||
charsToCopy = _uncheckedCharOffset(colsToCopy);
|
||||
// Safety: colsToCopy is [0, _columnCount] due to colsToCopy != 0.
|
||||
for (; colsToCopy != 0 && _uncheckedIsTrailer(colsToCopy); --colsToCopy)
|
||||
{
|
||||
}
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
_rowWidth = width;
|
||||
// If we grow the row width, we have to append a bunch of whitespace.
|
||||
// `trailingWhitespace` stores that amount.
|
||||
// Safety: The preceding block left colsToCopy in the range [0, rowWidth].
|
||||
const uint16_t trailingWhitespace = rowWidth - colsToCopy;
|
||||
|
||||
return S_OK;
|
||||
// Allocate memory for the new `_chars` array.
|
||||
// Use the provided charsBuffer if possible, otherwise allocate a `_charsHeap`.
|
||||
std::unique_ptr<wchar_t[]> charsHeap;
|
||||
std::span chars{ charsBuffer, rowWidth };
|
||||
const std::span charOffsets{ charOffsetsBuffer, ::base::strict_cast<size_t>(rowWidth) + 1u };
|
||||
if (const uint16_t charsCapacity = charsToCopy + trailingWhitespace; charsCapacity > rowWidth)
|
||||
{
|
||||
charsHeap = std::make_unique_for_overwrite<wchar_t[]>(charsCapacity);
|
||||
chars = { charsHeap.get(), charsCapacity };
|
||||
}
|
||||
|
||||
// Copy chars and charOffsets over.
|
||||
{
|
||||
const auto it = std::copy_n(_chars.begin(), charsToCopy, chars.begin());
|
||||
std::fill_n(it, trailingWhitespace, L' ');
|
||||
}
|
||||
{
|
||||
const auto it = std::copy_n(_charOffsets.begin(), colsToCopy, charOffsets.begin());
|
||||
// The _charOffsets array is 1 wider than newWidth indicates.
|
||||
// This is because the extra column contains the past-the-end index into _chars.
|
||||
iota_n(it, trailingWhitespace + 1u, charsToCopy);
|
||||
}
|
||||
|
||||
_charsBuffer = charsBuffer;
|
||||
_charsHeap = std::move(charsHeap);
|
||||
_chars = chars;
|
||||
_charOffsets = charOffsets;
|
||||
_columnCount = rowWidth;
|
||||
|
||||
// .resize_trailing_extent() doesn't work if the vector is empty,
|
||||
// since there's no trailing item that could be extended.
|
||||
if (_attr.empty())
|
||||
{
|
||||
_attr = { rowWidth, fillAttribute };
|
||||
}
|
||||
else
|
||||
{
|
||||
_attr.resize_trailing_extent(rowWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void ROW::TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& attr, til::CoordType newWidth)
|
||||
{
|
||||
_attr = attr;
|
||||
_attr.resize_trailing_extent(gsl::narrow<uint16_t>(newWidth));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -78,20 +235,10 @@ bool ROW::Reset(const TextAttribute Attr)
|
||||
// - column - 0-indexed column index
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void ROW::ClearColumn(const til::CoordType column)
|
||||
void ROW::ClearCell(const til::CoordType column)
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, column >= _charRow.size());
|
||||
_charRow.ClearCell(column);
|
||||
}
|
||||
|
||||
UnicodeStorage& ROW::GetUnicodeStorage() noexcept
|
||||
{
|
||||
return _pParent->GetUnicodeStorage();
|
||||
}
|
||||
|
||||
const UnicodeStorage& ROW::GetUnicodeStorage() const noexcept
|
||||
{
|
||||
return _pParent->GetUnicodeStorage();
|
||||
static constexpr std::wstring_view space{ L" " };
|
||||
ReplaceCharacters(column, 1, space);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -103,17 +250,17 @@ const UnicodeStorage& ROW::GetUnicodeStorage() const noexcept
|
||||
// - limitRight - right inclusive column ID for the last write in this row. (optional, will just write to the end of row if nullopt)
|
||||
// Return Value:
|
||||
// - iterator to first cell that was not written to this row.
|
||||
OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType index, const std::optional<bool> wrap, std::optional<til::CoordType> limitRight)
|
||||
OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType columnBegin, const std::optional<bool> wrap, std::optional<til::CoordType> limitRight)
|
||||
{
|
||||
THROW_HR_IF(E_INVALIDARG, index >= _charRow.size());
|
||||
THROW_HR_IF(E_INVALIDARG, limitRight.value_or(0) >= _charRow.size());
|
||||
THROW_HR_IF(E_INVALIDARG, columnBegin >= size());
|
||||
THROW_HR_IF(E_INVALIDARG, limitRight.value_or(0) >= size());
|
||||
|
||||
// If we're given a right-side column limit, use it. Otherwise, the write limit is the final column index available in the char row.
|
||||
const auto finalColumnInRow = limitRight.value_or(_charRow.size() - 1);
|
||||
const auto finalColumnInRow = limitRight.value_or(size() - 1);
|
||||
|
||||
auto currentColor = it->TextAttr();
|
||||
uint16_t colorUses = 0;
|
||||
auto colorStarts = gsl::narrow_cast<uint16_t>(index);
|
||||
auto colorStarts = gsl::narrow_cast<uint16_t>(columnBegin);
|
||||
auto currentIndex = colorStarts;
|
||||
|
||||
while (it && currentIndex <= finalColumnInRow)
|
||||
@@ -131,7 +278,7 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType i
|
||||
{
|
||||
// Otherwise, commit this color into the run and save off the new one.
|
||||
// Now commit the new color runs into the attr row.
|
||||
_attrRow.Replace(colorStarts, currentIndex, currentColor);
|
||||
_attr.replace(colorStarts, currentIndex, currentColor);
|
||||
currentColor = it->TextAttr();
|
||||
colorUses = 1;
|
||||
colorStarts = currentIndex;
|
||||
@@ -141,31 +288,47 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType i
|
||||
// Fill the text if the behavior isn't set to saying there's only a color stored in this iterator.
|
||||
if (it->TextAttrBehavior() != TextAttributeBehavior::StoredOnly)
|
||||
{
|
||||
const auto fillingFirstColumn = currentIndex == 0;
|
||||
const auto fillingLastColumn = currentIndex == finalColumnInRow;
|
||||
const auto attr = it->DbcsAttr();
|
||||
const auto& chars = it->Chars();
|
||||
|
||||
// TODO: MSFT: 19452170 - We need to ensure when writing any trailing byte that the one to the left
|
||||
// is a matching leading byte. Likewise, if we're writing a leading byte, we need to make sure we still have space in this loop
|
||||
// for the trailing byte coming up before writing it.
|
||||
|
||||
// If we're trying to fill the first cell with a trailing byte, pad it out instead by clearing it.
|
||||
// Don't increment iterator. We'll advance the index and try again with this value on the next round through the loop.
|
||||
if (currentIndex == 0 && it->DbcsAttr().IsTrailing())
|
||||
switch (attr)
|
||||
{
|
||||
_charRow.ClearCell(currentIndex);
|
||||
}
|
||||
// If we're trying to fill the last cell with a leading byte, pad it out instead by clearing it.
|
||||
// Don't increment iterator. We'll exit because we couldn't write a lead at the end of a line.
|
||||
else if (fillingLastColumn && it->DbcsAttr().IsLeading())
|
||||
{
|
||||
_charRow.ClearCell(currentIndex);
|
||||
SetDoubleBytePadded(true);
|
||||
}
|
||||
// Otherwise, copy the data given and increment the iterator.
|
||||
else
|
||||
{
|
||||
_charRow.DbcsAttrAt(currentIndex) = it->DbcsAttr();
|
||||
_charRow.GlyphAt(currentIndex) = it->Chars();
|
||||
case DbcsAttribute::Leading:
|
||||
if (fillingLastColumn)
|
||||
{
|
||||
// The wide char doesn't fit. Pad with whitespace.
|
||||
// Don't increment the iterator. Instead we'll return from this function and the
|
||||
// caller can call WriteCells() again on the next row with the same iterator position.
|
||||
ClearCell(currentIndex);
|
||||
SetDoubleBytePadded(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReplaceCharacters(currentIndex, 2, chars);
|
||||
++it;
|
||||
}
|
||||
break;
|
||||
case DbcsAttribute::Trailing:
|
||||
// Handling the trailing half of wide chars ensures that we correctly restore
|
||||
// wide characters when a user backs up and restores the viewport via CHAR_INFOs.
|
||||
if (fillingFirstColumn)
|
||||
{
|
||||
// The wide char doesn't fit. Pad with whitespace.
|
||||
// Ignore the character. There's no correct alternative way to handle this situation.
|
||||
ClearCell(currentIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReplaceCharacters(currentIndex - 1, 2, chars);
|
||||
}
|
||||
++it;
|
||||
break;
|
||||
default:
|
||||
ReplaceCharacters(currentIndex, 1, chars);
|
||||
++it;
|
||||
break;
|
||||
}
|
||||
|
||||
// If we're asked to (un)set the wrap status and we just filled the last column with some text...
|
||||
@@ -191,8 +354,334 @@ OutputCellIterator ROW::WriteCells(OutputCellIterator it, const til::CoordType i
|
||||
// Now commit the final color into the attr row
|
||||
if (colorUses)
|
||||
{
|
||||
_attrRow.Replace(colorStarts, currentIndex, currentColor);
|
||||
_attr.replace(colorStarts, currentIndex, currentColor);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
bool ROW::SetAttrToEnd(const til::CoordType columnBegin, const TextAttribute attr)
|
||||
{
|
||||
_attr.replace(_clampedColumnInclusive(columnBegin), _attr.size(), attr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ROW::ReplaceAttributes(const til::CoordType beginIndex, const til::CoordType endIndex, const TextAttribute& newAttr)
|
||||
{
|
||||
_attr.replace(_clampedColumnInclusive(beginIndex), _clampedColumnInclusive(endIndex), newAttr);
|
||||
}
|
||||
|
||||
void ROW::ReplaceCharacters(til::CoordType columnBegin, til::CoordType width, const std::wstring_view& chars)
|
||||
{
|
||||
const auto colBeg = _clampedUint16(columnBegin);
|
||||
const auto colEnd = _clampedUint16(columnBegin + width);
|
||||
|
||||
if (colBeg >= colEnd || colEnd > _columnCount || chars.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Safety:
|
||||
// * colBeg is now [0, _columnCount)
|
||||
// * colEnd is now (colBeg, _columnCount]
|
||||
|
||||
// Algorithm explanation
|
||||
//
|
||||
// Task:
|
||||
// Replace the characters in cells [colBeg, colEnd) with a single `width`-wide glyph consisting of `chars`.
|
||||
//
|
||||
// Problem:
|
||||
// Imagine that we have the following ROW contents:
|
||||
// "xxyyzz"
|
||||
// xx, yy, zz are 2 cell wide glyphs. We want to insert a 2 cell wide glyph ww at colBeg 1:
|
||||
// ^^
|
||||
// ww
|
||||
// An incorrect result would be:
|
||||
// "xwwyzz"
|
||||
// The half cut off x and y glyph wouldn't make much sense, so we need to fill them with whitespace:
|
||||
// " ww zz"
|
||||
//
|
||||
// Solution:
|
||||
// Given the range we want to replace [colBeg, colEnd), we "extend" it to encompass leading (preceding)
|
||||
// and trailing wide glyphs we partially overwrite resulting in the range [colExtBeg, colExtEnd), where
|
||||
// colExtBeg <= colBeg and colExtEnd >= colEnd. In other words, the to be replaced range has been "extended".
|
||||
// The amount of leading whitespace we need to insert is thus colBeg - colExtBeg
|
||||
// and the amount of trailing whitespace colExtEnd - colEnd.
|
||||
|
||||
// Extend range downwards (leading whitespace)
|
||||
uint16_t colExtBeg = colBeg;
|
||||
// Safety: colExtBeg is [0, _columnCount], because colBeg is.
|
||||
const uint16_t chExtBeg = _uncheckedCharOffset(colExtBeg);
|
||||
// Safety: colExtBeg remains [0, _columnCount] due to colExtBeg != 0.
|
||||
for (; colExtBeg != 0 && _uncheckedIsTrailer(colExtBeg); --colExtBeg)
|
||||
{
|
||||
}
|
||||
|
||||
// Extend range upwards (trailing whitespace)
|
||||
uint16_t colExtEnd = colEnd;
|
||||
// Safety: colExtEnd cannot be incremented past _columnCount, because the last
|
||||
// _charOffset at index _columnCount will never get the CharOffsetsTrailer flag.
|
||||
for (; _uncheckedIsTrailer(colExtEnd); ++colExtEnd)
|
||||
{
|
||||
}
|
||||
// Safety: After the previous loop colExtEnd is [0, _columnCount].
|
||||
const uint16_t chExtEnd = _uncheckedCharOffset(colExtEnd);
|
||||
|
||||
const uint16_t leadingSpaces = colBeg - colExtBeg;
|
||||
const uint16_t trailingSpaces = colExtEnd - colEnd;
|
||||
const size_t chExtEndNew = chars.size() + leadingSpaces + trailingSpaces + chExtBeg;
|
||||
|
||||
if (chExtEndNew != chExtEnd)
|
||||
{
|
||||
_resizeChars(colExtEnd, chExtBeg, chExtEnd, chExtEndNew);
|
||||
}
|
||||
|
||||
// Add leading/trailing whitespace and copy chars
|
||||
{
|
||||
auto it = _chars.begin() + chExtBeg;
|
||||
it = fill_n_small(it, leadingSpaces, L' ');
|
||||
it = copy_n_small(chars.begin(), chars.size(), it);
|
||||
it = fill_n_small(it, trailingSpaces, L' ');
|
||||
}
|
||||
// Update char offsets with leading/trailing whitespace and the chars columns.
|
||||
{
|
||||
auto chPos = chExtBeg;
|
||||
auto it = _charOffsets.begin() + colExtBeg;
|
||||
|
||||
it = iota_n_mut(it, leadingSpaces, chPos);
|
||||
|
||||
*it++ = chPos;
|
||||
it = fill_small(it, _charOffsets.begin() + colEnd, gsl::narrow_cast<uint16_t>(chPos | CharOffsetsTrailer));
|
||||
chPos = gsl::narrow_cast<uint16_t>(chPos + chars.size());
|
||||
|
||||
it = iota_n_mut(it, trailingSpaces, chPos);
|
||||
}
|
||||
}
|
||||
|
||||
// This function represents the slow path of ReplaceCharacters(),
|
||||
// as it reallocates the backing buffer and shifts the char offsets.
|
||||
// The parameters are difficult to explain, but their names are identical to
|
||||
// local variables in ReplaceCharacters() which I've attempted to document there.
|
||||
void ROW::_resizeChars(uint16_t colExtEnd, uint16_t chExtBeg, uint16_t chExtEnd, size_t chExtEndNew)
|
||||
{
|
||||
const auto diff = chExtEndNew - chExtEnd;
|
||||
const auto currentLength = _charSize();
|
||||
const auto newLength = currentLength + diff;
|
||||
|
||||
if (newLength <= _chars.size())
|
||||
{
|
||||
std::copy_n(_chars.begin() + chExtEnd, currentLength - chExtEnd, _chars.begin() + chExtEndNew);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto minCapacity = std::min<size_t>(UINT16_MAX, _chars.size() + (_chars.size() >> 1));
|
||||
const auto newCapacity = gsl::narrow<uint16_t>(std::max(newLength, minCapacity));
|
||||
|
||||
auto charsHeap = std::make_unique_for_overwrite<wchar_t[]>(newCapacity);
|
||||
const std::span chars{ charsHeap.get(), newCapacity };
|
||||
|
||||
std::copy_n(_chars.begin(), chExtBeg, chars.begin());
|
||||
std::copy_n(_chars.begin() + chExtEnd, currentLength - chExtEnd, chars.begin() + chExtEndNew);
|
||||
|
||||
_charsHeap = std::move(charsHeap);
|
||||
_chars = chars;
|
||||
}
|
||||
|
||||
auto it = _charOffsets.begin() + colExtEnd;
|
||||
const auto end = _charOffsets.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
*it = gsl::narrow_cast<uint16_t>(*it + diff);
|
||||
}
|
||||
}
|
||||
|
||||
const til::small_rle<TextAttribute, uint16_t, 1>& ROW::Attributes() const noexcept
|
||||
{
|
||||
return _attr;
|
||||
}
|
||||
|
||||
TextAttribute ROW::GetAttrByColumn(const til::CoordType column) const
|
||||
{
|
||||
return _attr.at(_clampedUint16(column));
|
||||
}
|
||||
|
||||
std::vector<uint16_t> ROW::GetHyperlinks() const
|
||||
{
|
||||
std::vector<uint16_t> ids;
|
||||
for (const auto& run : _attr.runs())
|
||||
{
|
||||
if (run.value.IsHyperlink())
|
||||
{
|
||||
ids.emplace_back(run.value.GetHyperlinkId());
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
uint16_t ROW::size() const noexcept
|
||||
{
|
||||
return _columnCount;
|
||||
}
|
||||
|
||||
til::CoordType ROW::MeasureLeft() const noexcept
|
||||
{
|
||||
const auto text = GetText();
|
||||
const auto beg = text.begin();
|
||||
const auto end = text.end();
|
||||
auto it = beg;
|
||||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (*it != L' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return gsl::narrow_cast<til::CoordType>(it - beg);
|
||||
}
|
||||
|
||||
til::CoordType ROW::MeasureRight() const noexcept
|
||||
{
|
||||
const auto text = GetText();
|
||||
const auto beg = text.begin();
|
||||
const auto end = text.end();
|
||||
auto it = end;
|
||||
|
||||
for (; it != beg; --it)
|
||||
{
|
||||
// it[-1] is safe as `it` is always greater than `beg` (loop invariant).
|
||||
if (til::at(it, -1) != L' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We're supposed to return the measurement in cells and not characters
|
||||
// and therefore simply calculating `it - beg` would be wrong.
|
||||
//
|
||||
// An example: The row is 10 cells wide and `it` points to the second character.
|
||||
// `it - beg` would return 1, but it's possible it's actually 1 wide glyph and 8 whitespace.
|
||||
return gsl::narrow_cast<til::CoordType>(_columnCount - (end - it));
|
||||
}
|
||||
|
||||
bool ROW::ContainsText() const noexcept
|
||||
{
|
||||
const auto text = GetText();
|
||||
const auto beg = text.begin();
|
||||
const auto end = text.end();
|
||||
auto it = beg;
|
||||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (*it != L' ')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring_view ROW::GlyphAt(til::CoordType column) const noexcept
|
||||
{
|
||||
auto col = _clampedColumn(column);
|
||||
|
||||
// Safety: col is [0, _columnCount).
|
||||
const auto beg = _uncheckedCharOffset(col);
|
||||
// Safety: col cannot be incremented past _columnCount, because the last
|
||||
// _charOffset at index _columnCount will never get the CharOffsetsTrailer flag.
|
||||
while (_uncheckedIsTrailer(++col))
|
||||
{
|
||||
}
|
||||
// Safety: col is now (0, _columnCount].
|
||||
const auto end = _uncheckedCharOffset(col);
|
||||
|
||||
return { _chars.begin() + beg, _chars.begin() + end };
|
||||
}
|
||||
|
||||
DbcsAttribute ROW::DbcsAttrAt(til::CoordType column) const noexcept
|
||||
{
|
||||
const auto col = _clampedColumn(column);
|
||||
|
||||
auto attr = DbcsAttribute::Single;
|
||||
// Safety: col is [0, _columnCount).
|
||||
if (_uncheckedIsTrailer(col))
|
||||
{
|
||||
attr = DbcsAttribute::Trailing;
|
||||
}
|
||||
// Safety: col+1 is [1, _columnCount].
|
||||
else if (_uncheckedIsTrailer(::base::strict_cast<size_t>(col) + 1u))
|
||||
{
|
||||
attr = DbcsAttribute::Leading;
|
||||
}
|
||||
|
||||
return { attr };
|
||||
}
|
||||
|
||||
std::wstring_view ROW::GetText() const noexcept
|
||||
{
|
||||
return { _chars.data(), _charSize() };
|
||||
}
|
||||
|
||||
DelimiterClass ROW::DelimiterClassAt(til::CoordType column, const std::wstring_view& wordDelimiters) const noexcept
|
||||
{
|
||||
const auto col = _clampedColumn(column);
|
||||
// Safety: col is [0, _columnCount).
|
||||
const auto glyph = _uncheckedChar(_uncheckedCharOffset(col));
|
||||
|
||||
if (glyph <= L' ')
|
||||
{
|
||||
return DelimiterClass::ControlChar;
|
||||
}
|
||||
else if (wordDelimiters.find(glyph) != std::wstring_view::npos)
|
||||
{
|
||||
return DelimiterClass::DelimiterChar;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DelimiterClass::RegularChar;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr uint16_t ROW::_clampedUint16(T v) noexcept
|
||||
{
|
||||
return static_cast<uint16_t>(std::max(T{ 0 }, std::min(T{ 65535 }, v)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr uint16_t ROW::_clampedColumn(T v) const noexcept
|
||||
{
|
||||
return static_cast<uint16_t>(std::max(T{ 0 }, std::min<T>(_columnCount - 1u, v)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr uint16_t ROW::_clampedColumnInclusive(T v) const noexcept
|
||||
{
|
||||
return static_cast<uint16_t>(std::max(T{ 0 }, std::min<T>(_columnCount, v)));
|
||||
}
|
||||
|
||||
// Safety: off must be [0, _charSize()].
|
||||
wchar_t ROW::_uncheckedChar(size_t off) const noexcept
|
||||
{
|
||||
return til::at(_chars, off);
|
||||
}
|
||||
|
||||
uint16_t ROW::_charSize() const noexcept
|
||||
{
|
||||
// Safety: _charOffsets is an array of `_columnCount + 1` entries.
|
||||
return til::at(_charOffsets, _columnCount);
|
||||
}
|
||||
|
||||
// Safety: col must be [0, _columnCount].
|
||||
uint16_t ROW::_uncheckedCharOffset(size_t col) const noexcept
|
||||
{
|
||||
return til::at(_charOffsets, col) & CharOffsetsMask;
|
||||
}
|
||||
|
||||
// Safety: col must be [0, _columnCount].
|
||||
bool ROW::_uncheckedIsTrailer(size_t col) const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(til::at(_charOffsets, col), CharOffsetsTrailer);
|
||||
}
|
||||
|
||||
@@ -20,50 +20,68 @@ Revision History:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AttrRow.hpp"
|
||||
#include <span>
|
||||
|
||||
#include <til/rle.h>
|
||||
|
||||
#include "LineRendition.hpp"
|
||||
#include "OutputCell.hpp"
|
||||
#include "OutputCellIterator.hpp"
|
||||
#include "CharRow.hpp"
|
||||
#include "UnicodeStorage.hpp"
|
||||
|
||||
class TextBuffer;
|
||||
|
||||
enum class DelimiterClass
|
||||
{
|
||||
ControlChar,
|
||||
DelimiterChar,
|
||||
RegularChar
|
||||
};
|
||||
|
||||
class ROW final
|
||||
{
|
||||
public:
|
||||
ROW(const til::CoordType rowId, const til::CoordType rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent);
|
||||
ROW() = default;
|
||||
ROW(wchar_t* charsBuffer, uint16_t* charOffsetsBuffer, uint16_t rowWidth, const TextAttribute& fillAttribute);
|
||||
|
||||
til::CoordType size() const noexcept { return _rowWidth; }
|
||||
ROW(const ROW& other) = delete;
|
||||
ROW& operator=(const ROW& other) = delete;
|
||||
|
||||
void SetWrapForced(const bool wrap) noexcept { _wrapForced = wrap; }
|
||||
bool WasWrapForced() const noexcept { return _wrapForced; }
|
||||
explicit ROW(ROW&& other) = default;
|
||||
ROW& operator=(ROW&& other) = default;
|
||||
|
||||
void SetDoubleBytePadded(const bool doubleBytePadded) noexcept { _doubleBytePadded = doubleBytePadded; }
|
||||
bool WasDoubleBytePadded() const noexcept { return _doubleBytePadded; }
|
||||
friend void swap(ROW& lhs, ROW& rhs) noexcept;
|
||||
|
||||
const CharRow& GetCharRow() const noexcept { return _charRow; }
|
||||
CharRow& GetCharRow() noexcept { return _charRow; }
|
||||
void SetWrapForced(const bool wrap) noexcept;
|
||||
bool WasWrapForced() const noexcept;
|
||||
void SetDoubleBytePadded(const bool doubleBytePadded) noexcept;
|
||||
bool WasDoubleBytePadded() const noexcept;
|
||||
void SetLineRendition(const LineRendition lineRendition) noexcept;
|
||||
LineRendition GetLineRendition() const noexcept;
|
||||
|
||||
const ATTR_ROW& GetAttrRow() const noexcept { return _attrRow; }
|
||||
ATTR_ROW& GetAttrRow() noexcept { return _attrRow; }
|
||||
void Reset(const TextAttribute& attr);
|
||||
void Resize(wchar_t* charsBuffer, uint16_t* charOffsetsBuffer, uint16_t rowWidth, const TextAttribute& fillAttribute);
|
||||
void TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& attr, til::CoordType newWidth);
|
||||
|
||||
LineRendition GetLineRendition() const noexcept { return _lineRendition; }
|
||||
void SetLineRendition(const LineRendition lineRendition) noexcept { _lineRendition = lineRendition; }
|
||||
void ClearCell(til::CoordType column);
|
||||
OutputCellIterator WriteCells(OutputCellIterator it, til::CoordType columnBegin, std::optional<bool> wrap = std::nullopt, std::optional<til::CoordType> limitRight = std::nullopt);
|
||||
bool SetAttrToEnd(til::CoordType columnBegin, TextAttribute attr);
|
||||
void ReplaceAttributes(til::CoordType beginIndex, til::CoordType endIndex, const TextAttribute& newAttr);
|
||||
void ReplaceCharacters(til::CoordType columnBegin, til::CoordType width, const std::wstring_view& chars);
|
||||
|
||||
til::CoordType GetId() const noexcept { return _id; }
|
||||
void SetId(const til::CoordType id) noexcept { _id = id; }
|
||||
const til::small_rle<TextAttribute, uint16_t, 1>& Attributes() const noexcept;
|
||||
TextAttribute GetAttrByColumn(til::CoordType column) const;
|
||||
std::vector<uint16_t> GetHyperlinks() const;
|
||||
uint16_t size() const noexcept;
|
||||
til::CoordType MeasureLeft() const noexcept;
|
||||
til::CoordType MeasureRight() const noexcept;
|
||||
bool ContainsText() const noexcept;
|
||||
std::wstring_view GlyphAt(til::CoordType column) const noexcept;
|
||||
DbcsAttribute DbcsAttrAt(til::CoordType column) const noexcept;
|
||||
std::wstring_view GetText() const noexcept;
|
||||
DelimiterClass DelimiterClassAt(til::CoordType column, const std::wstring_view& wordDelimiters) const noexcept;
|
||||
|
||||
bool Reset(const TextAttribute Attr);
|
||||
[[nodiscard]] HRESULT Resize(const til::CoordType width);
|
||||
|
||||
void ClearColumn(const til::CoordType column);
|
||||
std::wstring GetText() const { return _charRow.GetText(); }
|
||||
|
||||
UnicodeStorage& GetUnicodeStorage() noexcept;
|
||||
const UnicodeStorage& GetUnicodeStorage() const noexcept;
|
||||
|
||||
OutputCellIterator WriteCells(OutputCellIterator it, const til::CoordType index, const std::optional<bool> wrap = std::nullopt, std::optional<til::CoordType> limitRight = std::nullopt);
|
||||
auto AttrBegin() const noexcept { return _attr.begin(); }
|
||||
auto AttrEnd() const noexcept { return _attr.end(); }
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend constexpr bool operator==(const ROW& a, const ROW& b) noexcept;
|
||||
@@ -71,23 +89,84 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
CharRow _charRow;
|
||||
ATTR_ROW _attrRow;
|
||||
LineRendition _lineRendition;
|
||||
til::CoordType _id;
|
||||
til::CoordType _rowWidth;
|
||||
// To simplify the detection of wide glyphs, we don't just store the simple character offset as described
|
||||
// for _charOffsets. Instead we use the most significant bit to indicate whether any column is the
|
||||
// trailing half of a wide glyph. This simplifies many implementation details via _uncheckedIsTrailer.
|
||||
static constexpr uint16_t CharOffsetsTrailer = 0x8000;
|
||||
static constexpr uint16_t CharOffsetsMask = 0x7fff;
|
||||
|
||||
template<typename T>
|
||||
static constexpr uint16_t _clampedUint16(T v) noexcept;
|
||||
template<typename T>
|
||||
constexpr uint16_t _clampedColumn(T v) const noexcept;
|
||||
template<typename T>
|
||||
constexpr uint16_t _clampedColumnInclusive(T v) const noexcept;
|
||||
|
||||
wchar_t _uncheckedChar(size_t off) const noexcept;
|
||||
uint16_t _charSize() const noexcept;
|
||||
uint16_t _uncheckedCharOffset(size_t col) const noexcept;
|
||||
bool _uncheckedIsTrailer(size_t col) const noexcept;
|
||||
|
||||
void _init() noexcept;
|
||||
void _resizeChars(uint16_t colExtEnd, uint16_t chExtBeg, uint16_t chExtEnd, size_t chExtEndNew);
|
||||
|
||||
// These fields are a bit "wasteful", but it makes all this a bit more robust against
|
||||
// programming errors during initial development (which is when this comment was written).
|
||||
// * _chars and _charsHeap are redundant
|
||||
// If _charsHeap is stored in _chars, we can still infer that
|
||||
// _chars was allocated on the heap if _chars != _charsBuffer.
|
||||
// * _chars doesn't need a size_t size()
|
||||
// The size may never exceed an uint16_t anyways.
|
||||
// * _charOffsets doesn't need a size() at all
|
||||
// The length is already stored in _columns.
|
||||
|
||||
// Most text uses only a single wchar_t per codepoint / grapheme cluster.
|
||||
// That's why TextBuffer allocates a large blob of virtual memory which we can use as
|
||||
// a simplified chars buffer, without having to allocate any additional heap memory.
|
||||
// _charsBuffer fits _columnCount characters at most.
|
||||
wchar_t* _charsBuffer = nullptr;
|
||||
// ...but if this ROW needs to store more than _columnCount characters
|
||||
// then it will allocate a larger string on the heap and store it here.
|
||||
// The capacity of this string on the heap is stored in _chars.size().
|
||||
std::unique_ptr<wchar_t[]> _charsHeap;
|
||||
// _chars either refers to our _charsBuffer or _charsHeap, defaulting to the former.
|
||||
// _chars.size() is NOT the length of the string, but rather its capacity.
|
||||
// _charOffsets[_columnCount] stores the length.
|
||||
std::span<wchar_t> _chars;
|
||||
// _charOffsets accelerates indexing into the above _chars string given a terminal column,
|
||||
// by storing the character index/offset at which a column's text in _chars starts.
|
||||
// It stores 1 more item than this row is wide, allowing it to store the
|
||||
// past-the-end offset, which is thus equal to the length of the string.
|
||||
//
|
||||
// For instance given a 4 column ROW containing "abcd" it would store 01234,
|
||||
// because each of "abcd" are 1 column wide and 1 wchar_t per column.
|
||||
// Given "a\u732Bd" it would store 01123, because "\u732B" is a wide glyph
|
||||
// and "11" indicates that both column 1 and 2 start at &_chars[1] (= wide glyph).
|
||||
// The fact that the next offset is 2 tells us that the glyph is 1 wchar_t long.
|
||||
// Given "a\uD83D\uDE00d" ("\uD83D\uDE00" is an Emoji) it would store 01134,
|
||||
// because while it's 2 cells wide as indicated by 2 offsets that are identical (11),
|
||||
// the next offset is 3, which indicates that the glyph is 3-1 = 2 wchar_t long.
|
||||
//
|
||||
// In other words, _charOffsets tells us both the width in chars and width in columns.
|
||||
// See CharOffsetsTrailer for more information.
|
||||
std::span<uint16_t> _charOffsets;
|
||||
// _attr is a run-length-encoded vector of TextAttribute with a decompressed
|
||||
// length equal to _columnCount (= 1 TextAttribute per column).
|
||||
til::small_rle<TextAttribute, uint16_t, 1> _attr;
|
||||
// The width of the row in visual columns.
|
||||
uint16_t _columnCount = 0;
|
||||
// Stores double-width/height (DECSWL/DECDWL/DECDHL) attributes.
|
||||
LineRendition _lineRendition = LineRendition::SingleWidth;
|
||||
// Occurs when the user runs out of text in a given row and we're forced to wrap the cursor to the next line
|
||||
bool _wrapForced;
|
||||
bool _wrapForced = false;
|
||||
// Occurs when the user runs out of text to support a double byte character and we're forced to the next line
|
||||
bool _doubleBytePadded;
|
||||
TextBuffer* _pParent; // non ownership pointer
|
||||
bool _doubleBytePadded = false;
|
||||
};
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
constexpr bool operator==(const ROW& a, const ROW& b) noexcept
|
||||
{
|
||||
// comparison is only used in the tests; this should suffice.
|
||||
return (a._pParent == b._pParent &&
|
||||
a._id == b._id);
|
||||
return a._charsBuffer == b._charsBuffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
// Keeping TextColor compact helps us keeping TextAttribute compact,
|
||||
// which in turn ensures that our buffer memory usage is low.
|
||||
static_assert(sizeof(TextAttribute) == 14);
|
||||
static_assert(sizeof(TextAttribute) == 12);
|
||||
static_assert(alignof(TextAttribute) == 2);
|
||||
// Ensure that we can memcpy() and memmove() the struct for performance.
|
||||
static_assert(std::is_trivially_copyable_v<TextAttribute>);
|
||||
@@ -116,7 +116,7 @@ WORD TextAttribute::GetLegacyAttributes() const noexcept
|
||||
{
|
||||
const auto fgIndex = _foreground.GetLegacyIndex(s_legacyDefaultForeground);
|
||||
const auto bgIndex = _background.GetLegacyIndex(s_legacyDefaultBackground);
|
||||
const WORD metaAttrs = _wAttrLegacy & META_ATTRS;
|
||||
const WORD metaAttrs = static_cast<WORD>(_attrs) & USED_META_ATTRS;
|
||||
const auto brighten = IsIntense() && _foreground.CanBeBrightened();
|
||||
return fgIndex | (bgIndex << 4) | metaAttrs | (brighten ? FOREGROUND_INTENSITY : 0);
|
||||
}
|
||||
@@ -217,151 +217,151 @@ void TextAttribute::SetHyperlinkId(uint16_t id) noexcept
|
||||
_hyperlinkId = id;
|
||||
}
|
||||
|
||||
bool TextAttribute::IsLeadingByte() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_LEADING_BYTE);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsTrailingByte() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_LEADING_BYTE);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsTopHorizontalDisplayed() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::TopGridline);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsBottomHorizontalDisplayed() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_UNDERSCORE);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::BottomGridline);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsLeftVerticalDisplayed() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_GRID_LVERTICAL);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::LeftGridline);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsRightVerticalDisplayed() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_GRID_RVERTICAL);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::RightGridline);
|
||||
}
|
||||
|
||||
void TextAttribute::SetLeftVerticalDisplayed(const bool isDisplayed) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_GRID_LVERTICAL, isDisplayed);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::LeftGridline, isDisplayed);
|
||||
}
|
||||
|
||||
void TextAttribute::SetRightVerticalDisplayed(const bool isDisplayed) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_GRID_RVERTICAL, isDisplayed);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::RightGridline, isDisplayed);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsIntense() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Intense);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Intense);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsFaint() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Faint);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Faint);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsItalic() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Italics);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Italics);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsBlinking() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Blinking);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Blinking);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsInvisible() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Invisible);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Invisible);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsCrossedOut() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::CrossedOut);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::CrossedOut);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsUnderlined() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Underlined);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Underlined);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsDoublyUnderlined() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::DoublyUnderlined);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::DoublyUnderlined);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsOverlined() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::TopGridline);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsReverseVideo() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO);
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::ReverseVideo);
|
||||
}
|
||||
|
||||
bool TextAttribute::IsProtected() const noexcept
|
||||
{
|
||||
return WI_IsFlagSet(_attrs, CharacterAttributes::Protected);
|
||||
}
|
||||
|
||||
void TextAttribute::SetIntense(bool isIntense) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Intense, isIntense);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::Intense, isIntense);
|
||||
}
|
||||
|
||||
void TextAttribute::SetFaint(bool isFaint) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Faint, isFaint);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::Faint, isFaint);
|
||||
}
|
||||
|
||||
void TextAttribute::SetItalic(bool isItalic) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Italics, isItalic);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::Italics, isItalic);
|
||||
}
|
||||
|
||||
void TextAttribute::SetBlinking(bool isBlinking) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Blinking, isBlinking);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::Blinking, isBlinking);
|
||||
}
|
||||
|
||||
void TextAttribute::SetInvisible(bool isInvisible) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Invisible, isInvisible);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::Invisible, isInvisible);
|
||||
}
|
||||
|
||||
void TextAttribute::SetCrossedOut(bool isCrossedOut) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::CrossedOut, isCrossedOut);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::CrossedOut, isCrossedOut);
|
||||
}
|
||||
|
||||
void TextAttribute::SetUnderlined(bool isUnderlined) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Underlined, isUnderlined);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::Underlined, isUnderlined);
|
||||
}
|
||||
|
||||
void TextAttribute::SetDoublyUnderlined(bool isDoublyUnderlined) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::DoublyUnderlined, isDoublyUnderlined);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::DoublyUnderlined, isDoublyUnderlined);
|
||||
}
|
||||
|
||||
void TextAttribute::SetOverlined(bool isOverlined) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL, isOverlined);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::TopGridline, isOverlined);
|
||||
}
|
||||
|
||||
void TextAttribute::SetReverseVideo(bool isReversed) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO, isReversed);
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::ReverseVideo, isReversed);
|
||||
}
|
||||
|
||||
void TextAttribute::SetProtected(bool isProtected) noexcept
|
||||
{
|
||||
WI_UpdateFlag(_attrs, CharacterAttributes::Protected, isProtected);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - swaps foreground and background color
|
||||
void TextAttribute::Invert() noexcept
|
||||
{
|
||||
WI_ToggleFlag(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO);
|
||||
WI_ToggleFlag(_attrs, CharacterAttributes::ReverseVideo);
|
||||
}
|
||||
|
||||
void TextAttribute::SetDefaultForeground() noexcept
|
||||
@@ -375,11 +375,11 @@ void TextAttribute::SetDefaultBackground() noexcept
|
||||
}
|
||||
|
||||
// Method description:
|
||||
// - Resets only the meta and extended attributes
|
||||
void TextAttribute::SetDefaultMetaAttrs() noexcept
|
||||
// - Resets only the rendition character attributes, which includes everything
|
||||
// except the Protected attribute.
|
||||
void TextAttribute::SetDefaultRenditionAttributes() noexcept
|
||||
{
|
||||
_extendedAttrs = ExtendedAttributes::Normal;
|
||||
_wAttrLegacy = 0;
|
||||
_attrs &= ~CharacterAttributes::Rendition;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -398,10 +398,11 @@ bool TextAttribute::BackgroundIsDefault() const noexcept
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Resets the meta and extended attributes, which is what the VT standard
|
||||
// requires for most erasing and filling operations.
|
||||
// - Resets the character attributes, which is what the VT standard
|
||||
// requires for most erasing and filling operations. In modern
|
||||
// applications it is also expected that hyperlinks are erased.
|
||||
void TextAttribute::SetStandardErase() noexcept
|
||||
{
|
||||
SetDefaultMetaAttrs();
|
||||
_attrs = CharacterAttributes::Normal;
|
||||
_hyperlinkId = 0;
|
||||
}
|
||||
|
||||
@@ -31,31 +31,26 @@ class TextAttribute final
|
||||
{
|
||||
public:
|
||||
constexpr TextAttribute() noexcept :
|
||||
_wAttrLegacy{ 0 },
|
||||
_attrs{ CharacterAttributes::Normal },
|
||||
_foreground{},
|
||||
_background{},
|
||||
_extendedAttrs{ ExtendedAttributes::Normal },
|
||||
_hyperlinkId{ 0 }
|
||||
{
|
||||
}
|
||||
|
||||
explicit constexpr TextAttribute(const WORD wLegacyAttr) noexcept :
|
||||
_wAttrLegacy{ gsl::narrow_cast<WORD>(wLegacyAttr & META_ATTRS) },
|
||||
_attrs{ gsl::narrow_cast<WORD>(wLegacyAttr & USED_META_ATTRS) },
|
||||
_foreground{ gsl::at(s_legacyForegroundColorMap, wLegacyAttr & FG_ATTRS) },
|
||||
_background{ gsl::at(s_legacyBackgroundColorMap, (wLegacyAttr & BG_ATTRS) >> 4) },
|
||||
_extendedAttrs{ ExtendedAttributes::Normal },
|
||||
_hyperlinkId{ 0 }
|
||||
{
|
||||
// If we're given lead/trailing byte information with the legacy color, strip it.
|
||||
WI_ClearAllFlags(_wAttrLegacy, COMMON_LVB_SBCSDBCS);
|
||||
}
|
||||
|
||||
constexpr TextAttribute(const COLORREF rgbForeground,
|
||||
const COLORREF rgbBackground) noexcept :
|
||||
_wAttrLegacy{ 0 },
|
||||
_attrs{ CharacterAttributes::Normal },
|
||||
_foreground{ rgbForeground },
|
||||
_background{ rgbBackground },
|
||||
_extendedAttrs{ ExtendedAttributes::Normal },
|
||||
_hyperlinkId{ 0 }
|
||||
{
|
||||
}
|
||||
@@ -64,8 +59,6 @@ public:
|
||||
static TextAttribute StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept;
|
||||
WORD GetLegacyAttributes() const noexcept;
|
||||
|
||||
bool IsLeadingByte() const noexcept;
|
||||
bool IsTrailingByte() const noexcept;
|
||||
bool IsTopHorizontalDisplayed() const noexcept;
|
||||
bool IsBottomHorizontalDisplayed() const noexcept;
|
||||
bool IsLeftVerticalDisplayed() const noexcept;
|
||||
@@ -97,6 +90,7 @@ public:
|
||||
bool IsDoublyUnderlined() const noexcept;
|
||||
bool IsOverlined() const noexcept;
|
||||
bool IsReverseVideo() const noexcept;
|
||||
bool IsProtected() const noexcept;
|
||||
|
||||
void SetIntense(bool isIntense) noexcept;
|
||||
void SetFaint(bool isFaint) noexcept;
|
||||
@@ -108,10 +102,15 @@ public:
|
||||
void SetDoublyUnderlined(bool isDoublyUnderlined) noexcept;
|
||||
void SetOverlined(bool isOverlined) noexcept;
|
||||
void SetReverseVideo(bool isReversed) noexcept;
|
||||
void SetProtected(bool isProtected) noexcept;
|
||||
|
||||
constexpr ExtendedAttributes GetExtendedAttributes() const noexcept
|
||||
constexpr void SetCharacterAttributes(const CharacterAttributes attrs) noexcept
|
||||
{
|
||||
return _extendedAttrs;
|
||||
_attrs = attrs;
|
||||
}
|
||||
constexpr CharacterAttributes GetCharacterAttributes() const noexcept
|
||||
{
|
||||
return _attrs;
|
||||
}
|
||||
|
||||
bool IsHyperlink() const noexcept;
|
||||
@@ -132,7 +131,7 @@ public:
|
||||
|
||||
void SetDefaultForeground() noexcept;
|
||||
void SetDefaultBackground() noexcept;
|
||||
void SetDefaultMetaAttrs() noexcept;
|
||||
void SetDefaultRenditionAttributes() noexcept;
|
||||
|
||||
bool BackgroundIsDefault() const noexcept;
|
||||
|
||||
@@ -149,38 +148,33 @@ public:
|
||||
const auto checkForeground = (inverted != IsReverseVideo());
|
||||
return !IsAnyGridLineEnabled() && // grid lines have a visual representation
|
||||
// crossed out, doubly and singly underlined have a visual representation
|
||||
WI_AreAllFlagsClear(_extendedAttrs, ExtendedAttributes::CrossedOut | ExtendedAttributes::DoublyUnderlined | ExtendedAttributes::Underlined) &&
|
||||
WI_AreAllFlagsClear(_attrs, CharacterAttributes::CrossedOut | CharacterAttributes::DoublyUnderlined | CharacterAttributes::Underlined) &&
|
||||
// hyperlinks have a visual representation
|
||||
!IsHyperlink() &&
|
||||
// all other attributes do not have a visual representation
|
||||
(_wAttrLegacy & META_ATTRS) == (other._wAttrLegacy & META_ATTRS) &&
|
||||
_attrs == other._attrs &&
|
||||
((checkForeground && _foreground == other._foreground) ||
|
||||
(!checkForeground && _background == other._background)) &&
|
||||
_extendedAttrs == other._extendedAttrs &&
|
||||
IsHyperlink() == other.IsHyperlink();
|
||||
}
|
||||
|
||||
constexpr bool IsAnyGridLineEnabled() const noexcept
|
||||
{
|
||||
return WI_IsAnyFlagSet(_wAttrLegacy, COMMON_LVB_GRID_HORIZONTAL | COMMON_LVB_GRID_LVERTICAL | COMMON_LVB_GRID_RVERTICAL | COMMON_LVB_UNDERSCORE);
|
||||
return WI_IsAnyFlagSet(_attrs, CharacterAttributes::TopGridline | CharacterAttributes::LeftGridline | CharacterAttributes::RightGridline | CharacterAttributes::BottomGridline);
|
||||
}
|
||||
constexpr bool HasAnyExtendedAttributes() const noexcept
|
||||
constexpr bool HasAnyVisualAttributes() const noexcept
|
||||
{
|
||||
return GetExtendedAttributes() != ExtendedAttributes::Normal ||
|
||||
IsAnyGridLineEnabled() ||
|
||||
GetHyperlinkId() != 0 ||
|
||||
IsReverseVideo();
|
||||
return GetCharacterAttributes() != CharacterAttributes::Normal || GetHyperlinkId() != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::array<TextColor, 16> s_legacyForegroundColorMap;
|
||||
static std::array<TextColor, 16> s_legacyBackgroundColorMap;
|
||||
|
||||
uint16_t _wAttrLegacy; // sizeof: 2, alignof: 2
|
||||
CharacterAttributes _attrs; // sizeof: 2, alignof: 2
|
||||
uint16_t _hyperlinkId; // sizeof: 2, alignof: 2
|
||||
TextColor _foreground; // sizeof: 4, alignof: 1
|
||||
TextColor _background; // sizeof: 4, alignof: 1
|
||||
ExtendedAttributes _extendedAttrs; // sizeof: 2, alignof: 2
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TextBufferTests;
|
||||
@@ -213,12 +207,11 @@ namespace WEX
|
||||
static WEX::Common::NoThrowString ToString(const TextAttribute& attr)
|
||||
{
|
||||
return WEX::Common::NoThrowString().Format(
|
||||
L"{FG:%s,BG:%s,intense:%d,wLegacy:(0x%04x),ext:(0x%02x)}",
|
||||
L"{FG:%s,BG:%s,intense:%d,attrs:(0x%02x)}",
|
||||
VerifyOutputTraits<TextColor>::ToString(attr._foreground).GetBuffer(),
|
||||
VerifyOutputTraits<TextColor>::ToString(attr._background).GetBuffer(),
|
||||
attr.IsIntense(),
|
||||
attr._wAttrLegacy,
|
||||
static_cast<DWORD>(attr._extendedAttrs));
|
||||
static_cast<DWORD>(attr._attrs));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "UnicodeStorage.hpp"
|
||||
|
||||
UnicodeStorage::UnicodeStorage() noexcept :
|
||||
_map{}
|
||||
{
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - fetches the text associated with key
|
||||
// Arguments:
|
||||
// - key - the key into the storage
|
||||
// Return Value:
|
||||
// - the glyph data associated with key
|
||||
// Note: will throw exception if key is not stored yet
|
||||
const UnicodeStorage::mapped_type& UnicodeStorage::GetText(const key_type key) const
|
||||
{
|
||||
return _map.at(key);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - stores glyph data associated with key.
|
||||
// Arguments:
|
||||
// - key - the key into the storage
|
||||
// - glyph - the glyph data to store
|
||||
void UnicodeStorage::StoreGlyph(const key_type key, const mapped_type& glyph)
|
||||
{
|
||||
_map.insert_or_assign(key, glyph);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - erases key and its associated data from the storage
|
||||
// Arguments:
|
||||
// - key - the key to remove
|
||||
void UnicodeStorage::Erase(const key_type key) noexcept
|
||||
{
|
||||
_map.erase(key);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Remaps all of the stored items to new coordinate positions
|
||||
// based on a bulk rearrangement of row IDs and potential row width resize.
|
||||
// Arguments:
|
||||
// - rowMap - A map of the old row IDs to the new row IDs.
|
||||
// - width - The width of the new row. Remove any items that are beyond the row width.
|
||||
// - Use nullopt if we're not resizing the width of the row, just renumbering the rows.
|
||||
void UnicodeStorage::Remap(const std::unordered_map<til::CoordType, til::CoordType>& rowMap, const std::optional<til::CoordType> width)
|
||||
{
|
||||
// Make a temporary map to hold all the new row positioning
|
||||
std::unordered_map<key_type, mapped_type> newMap;
|
||||
|
||||
// Walk through every stored item.
|
||||
for (const auto& pair : _map)
|
||||
{
|
||||
// Extract the old coordinate position
|
||||
const auto oldCoord = pair.first;
|
||||
|
||||
// Only try to short-circuit based on width if we were told it changed
|
||||
// by being given a new width value.
|
||||
if (width.has_value())
|
||||
{
|
||||
// Get the column ID
|
||||
const auto oldColId = oldCoord.X;
|
||||
|
||||
// If the column index is at/beyond the row width, don't bother copying it to the new map.
|
||||
if (oldColId >= width.value())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the row ID from the position as that's what we need to remap
|
||||
const auto oldRowId = oldCoord.Y;
|
||||
|
||||
// Use the mapping given to convert the old row ID to the new row ID
|
||||
const auto mapIter = rowMap.find(oldRowId);
|
||||
|
||||
// If there's no mapping to a new row, don't bother copying it to the new map. The row is gone.
|
||||
if (mapIter == rowMap.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto newRowId = mapIter->second;
|
||||
|
||||
// Generate a new coordinate with the same X as the old one, but a new Y value.
|
||||
const auto newCoord = til::point{ oldCoord.X, newRowId };
|
||||
|
||||
// Put the adjusted coordinate into the map with the original value.
|
||||
newMap.emplace(newCoord, pair.second);
|
||||
}
|
||||
|
||||
// Swap into the stored map, free the temporary when we exit.
|
||||
_map.swap(newMap);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- UnicodeStorage.hpp
|
||||
|
||||
Abstract:
|
||||
- dynamic storage location for glyphs that can't normally fit in the output buffer
|
||||
|
||||
Author(s):
|
||||
- Austin Diviness (AustDi) 02-May-2018
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <til/hash.h>
|
||||
|
||||
// std::unordered_map needs help to know how to hash a til::point
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<til::point>
|
||||
{
|
||||
// Routine Description:
|
||||
// - hashes a coord. coord will be hashed by storing the x and y values consecutively in the lower
|
||||
// bits of a size_t.
|
||||
// Arguments:
|
||||
// - coord - the coord to hash
|
||||
// Return Value:
|
||||
// - the hashed coord
|
||||
size_t operator()(const til::point coord) const noexcept
|
||||
{
|
||||
return til::hash(coord);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class UnicodeStorage final
|
||||
{
|
||||
public:
|
||||
using key_type = typename til::point;
|
||||
using mapped_type = typename std::vector<wchar_t>;
|
||||
|
||||
UnicodeStorage() noexcept;
|
||||
|
||||
const mapped_type& GetText(const key_type key) const;
|
||||
|
||||
void StoreGlyph(const key_type key, const mapped_type& glyph);
|
||||
|
||||
void Erase(const key_type key) noexcept;
|
||||
|
||||
void Remap(const std::unordered_map<til::CoordType, til::CoordType>& rowMap, const std::optional<til::CoordType> width);
|
||||
|
||||
private:
|
||||
std::unordered_map<key_type, mapped_type> _map;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class UnicodeStorageTests;
|
||||
friend class TextBufferTests;
|
||||
#endif
|
||||
};
|
||||
@@ -29,9 +29,7 @@ Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept :
|
||||
{
|
||||
}
|
||||
|
||||
Cursor::~Cursor()
|
||||
{
|
||||
}
|
||||
Cursor::~Cursor() = default;
|
||||
|
||||
til::point Cursor::GetPosition() const noexcept
|
||||
{
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<Import Project="$(SolutionDir)src\common.build.pre.props" />
|
||||
<Import Project="$(SolutionDir)src\common.nugetversions.props" />
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\AttrRow.cpp" />
|
||||
<ClCompile Include="..\cursor.cpp" />
|
||||
<ClCompile Include="..\OutputCell.cpp" />
|
||||
<ClCompile Include="..\OutputCellIterator.cpp" />
|
||||
@@ -24,16 +23,11 @@
|
||||
<ClCompile Include="..\textBuffer.cpp" />
|
||||
<ClCompile Include="..\textBufferCellIterator.cpp" />
|
||||
<ClCompile Include="..\textBufferTextIterator.cpp" />
|
||||
<ClCompile Include="..\CharRow.cpp" />
|
||||
<ClCompile Include="..\CharRowCell.cpp" />
|
||||
<ClCompile Include="..\CharRowCellReference.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\UnicodeStorage.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\AttrRow.hpp" />
|
||||
<ClInclude Include="..\cursor.h" />
|
||||
<ClInclude Include="..\DbcsAttribute.hpp" />
|
||||
<ClInclude Include="..\ICharRow.hpp" />
|
||||
@@ -49,11 +43,7 @@
|
||||
<ClInclude Include="..\textBuffer.hpp" />
|
||||
<ClInclude Include="..\textBufferCellIterator.hpp" />
|
||||
<ClInclude Include="..\textBufferTextIterator.hpp" />
|
||||
<ClInclude Include="..\CharRow.hpp" />
|
||||
<ClInclude Include="..\CharRowCell.hpp" />
|
||||
<ClInclude Include="..\CharRowCellReference.hpp" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
<ClInclude Include="..\UnicodeStorage.hpp" />
|
||||
</ItemGroup>
|
||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
|
||||
3
src/buffer/out/lib/sources.dep
Normal file
3
src/buffer/out/lib/sources.dep
Normal file
@@ -0,0 +1,3 @@
|
||||
BUILD_PASS1_CONSUMES= \
|
||||
onecore\windows\vcpkg|PASS1 \
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "search.h"
|
||||
|
||||
#include "CharRow.hpp"
|
||||
#include "textBuffer.hpp"
|
||||
#include "../types/inc/Utf16Parser.hpp"
|
||||
#include "../types/inc/GlyphWidth.hpp"
|
||||
|
||||
@@ -29,7 +29,6 @@ PRECOMPILED_CXX = 1
|
||||
PRECOMPILED_INCLUDE = ..\precomp.h
|
||||
|
||||
SOURCES= \
|
||||
..\AttrRow.cpp \
|
||||
..\cursor.cpp \
|
||||
..\OutputCell.cpp \
|
||||
..\OutputCellIterator.cpp \
|
||||
@@ -41,10 +40,6 @@ SOURCES= \
|
||||
..\textBuffer.cpp \
|
||||
..\textBufferCellIterator.cpp \
|
||||
..\textBufferTextIterator.cpp \
|
||||
..\CharRow.cpp \
|
||||
..\CharRowCell.cpp \
|
||||
..\CharRowCellReference.cpp \
|
||||
..\UnicodeStorage.cpp \
|
||||
..\search.cpp \
|
||||
|
||||
INCLUDES= \
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include "textBuffer.hpp"
|
||||
#include "CharRow.hpp"
|
||||
|
||||
#include <til/hash.h>
|
||||
|
||||
#include "../renderer/base/renderer.hpp"
|
||||
#include "../types/inc/utils.hpp"
|
||||
@@ -12,7 +13,74 @@
|
||||
#include "../../types/inc/Utf16Parser.hpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
#pragma hdrstop
|
||||
namespace
|
||||
{
|
||||
struct BufferAllocator
|
||||
{
|
||||
BufferAllocator(til::size sz)
|
||||
{
|
||||
const auto w = gsl::narrow<uint16_t>(sz.width);
|
||||
const auto h = gsl::narrow<uint16_t>(sz.height);
|
||||
|
||||
const auto charsBytes = w * sizeof(wchar_t);
|
||||
// The ROW::_indices array stores 1 more item than the buffer is wide.
|
||||
// That extra column stores the past-the-end _chars pointer.
|
||||
const auto indicesBytes = w * sizeof(uint16_t) + sizeof(uint16_t);
|
||||
const auto rowStride = charsBytes + indicesBytes;
|
||||
// 65535*65535 cells would result in a charsAreaSize of 8GiB.
|
||||
// --> Use uint64_t so that we can safely do our calculations even on x86.
|
||||
const auto allocSize = gsl::narrow<size_t>(::base::strict_cast<uint64_t>(rowStride) * ::base::strict_cast<uint64_t>(h));
|
||||
|
||||
_buffer = wil::unique_virtualalloc_ptr<std::byte>{ static_cast<std::byte*>(VirtualAlloc(nullptr, allocSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)) };
|
||||
THROW_IF_NULL_ALLOC(_buffer);
|
||||
|
||||
_data = std::span{ _buffer.get(), allocSize }.begin();
|
||||
_rowStride = rowStride;
|
||||
_indicesOffset = charsBytes;
|
||||
_width = w;
|
||||
_height = h;
|
||||
}
|
||||
|
||||
BufferAllocator& operator++() noexcept
|
||||
{
|
||||
_data += _rowStride;
|
||||
return *this;
|
||||
}
|
||||
|
||||
wchar_t* chars() const noexcept
|
||||
{
|
||||
return til::bit_cast<wchar_t*>(&*_data);
|
||||
}
|
||||
|
||||
uint16_t* indices() const noexcept
|
||||
{
|
||||
return til::bit_cast<uint16_t*>(&*(_data + _indicesOffset));
|
||||
}
|
||||
|
||||
uint16_t width() const noexcept
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
uint16_t height() const noexcept
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
wil::unique_virtualalloc_ptr<std::byte>&& take() noexcept
|
||||
{
|
||||
return std::move(_buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
wil::unique_virtualalloc_ptr<std::byte> _buffer;
|
||||
std::span<std::byte>::iterator _data;
|
||||
size_t _rowStride;
|
||||
size_t _indicesOffset;
|
||||
uint16_t _width;
|
||||
uint16_t _height;
|
||||
};
|
||||
}
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace Microsoft::Console::Types;
|
||||
@@ -35,24 +103,20 @@ TextBuffer::TextBuffer(const til::size screenBufferSize,
|
||||
const UINT cursorSize,
|
||||
const bool isActiveBuffer,
|
||||
Microsoft::Console::Render::Renderer& renderer) :
|
||||
_firstRow{ 0 },
|
||||
_renderer{ renderer },
|
||||
_currentAttributes{ defaultAttributes },
|
||||
_cursor{ cursorSize, *this },
|
||||
_storage{},
|
||||
_unicodeStorage{},
|
||||
_isActiveBuffer{ isActiveBuffer },
|
||||
_renderer{ renderer },
|
||||
_size{},
|
||||
_currentHyperlinkId{ 1 },
|
||||
_currentPatternId{ 0 }
|
||||
_isActiveBuffer{ isActiveBuffer }
|
||||
{
|
||||
// initialize ROWs
|
||||
_storage.reserve(gsl::narrow<size_t>(screenBufferSize.Y));
|
||||
for (til::CoordType i = 0; i < screenBufferSize.Y; ++i)
|
||||
BufferAllocator allocator{ screenBufferSize };
|
||||
|
||||
_storage.reserve(allocator.height());
|
||||
for (til::CoordType i = 0; i < screenBufferSize.Y; ++i, ++allocator)
|
||||
{
|
||||
_storage.emplace_back(i, screenBufferSize.X, _currentAttributes, this);
|
||||
_storage.emplace_back(allocator.chars(), allocator.indices(), allocator.width(), _currentAttributes);
|
||||
}
|
||||
|
||||
_charBuffer = allocator.take();
|
||||
_UpdateSize();
|
||||
}
|
||||
|
||||
@@ -199,10 +263,10 @@ bool TextBuffer::_AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribut
|
||||
// To figure out if the sequence is valid, we have to look at the character that comes before the current one
|
||||
const auto coordPrevPosition = _GetPreviousFromCursor();
|
||||
auto& prevRow = GetRowByOffset(coordPrevPosition.Y);
|
||||
DbcsAttribute prevDbcsAttr;
|
||||
DbcsAttribute prevDbcsAttr = DbcsAttribute::Single;
|
||||
try
|
||||
{
|
||||
prevDbcsAttr = prevRow.GetCharRow().DbcsAttrAt(coordPrevPosition.X);
|
||||
prevDbcsAttr = prevRow.DbcsAttrAt(coordPrevPosition.X);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -229,21 +293,21 @@ bool TextBuffer::_AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribut
|
||||
// T T Fail, uncorrectable. New trailing byte must have had leading before it.
|
||||
|
||||
// Check for only failing portions of the matrix:
|
||||
if (prevDbcsAttr.IsSingle() && dbcsAttribute.IsTrailing())
|
||||
if (prevDbcsAttr == DbcsAttribute::Single && dbcsAttribute == DbcsAttribute::Trailing)
|
||||
{
|
||||
// N, T failing case (uncorrectable)
|
||||
fValidSequence = false;
|
||||
}
|
||||
else if (prevDbcsAttr.IsLeading())
|
||||
else if (prevDbcsAttr == DbcsAttribute::Leading)
|
||||
{
|
||||
if (dbcsAttribute.IsSingle() || dbcsAttribute.IsLeading())
|
||||
if (dbcsAttribute == DbcsAttribute::Single || dbcsAttribute == DbcsAttribute::Leading)
|
||||
{
|
||||
// L, N and L, L failing cases (correctable)
|
||||
fValidSequence = false;
|
||||
fCorrectableByErase = true;
|
||||
}
|
||||
}
|
||||
else if (prevDbcsAttr.IsTrailing() && dbcsAttribute.IsTrailing())
|
||||
else if (prevDbcsAttr == DbcsAttribute::Trailing && dbcsAttribute == DbcsAttribute::Trailing)
|
||||
{
|
||||
// T, T failing case (uncorrectable)
|
||||
fValidSequence = false;
|
||||
@@ -255,7 +319,7 @@ bool TextBuffer::_AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribut
|
||||
// Erase previous character into an N type.
|
||||
try
|
||||
{
|
||||
prevRow.ClearColumn(coordPrevPosition.X);
|
||||
prevRow.ClearCell(coordPrevPosition.X);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -289,7 +353,7 @@ bool TextBuffer::_PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute
|
||||
auto fSuccess = true;
|
||||
// Now compensate if we don't have enough space for the upcoming double byte sequence
|
||||
// We only need to compensate for leading bytes
|
||||
if (dbcsAttribute.IsLeading())
|
||||
if (dbcsAttribute == DbcsAttribute::Leading)
|
||||
{
|
||||
const auto cursorPosition = GetCursor().GetPosition();
|
||||
const auto lineWidth = GetLineWidth(cursorPosition.Y);
|
||||
@@ -418,12 +482,20 @@ bool TextBuffer::InsertCharacter(const std::wstring_view chars,
|
||||
auto& Row = GetRowByOffset(iRow);
|
||||
|
||||
// Store character and double byte data
|
||||
auto& charRow = Row.GetCharRow();
|
||||
|
||||
try
|
||||
{
|
||||
charRow.GlyphAt(iCol) = chars;
|
||||
charRow.DbcsAttrAt(iCol) = dbcsAttribute;
|
||||
switch (dbcsAttribute)
|
||||
{
|
||||
case DbcsAttribute::Leading:
|
||||
Row.ReplaceCharacters(iCol, 2, chars);
|
||||
break;
|
||||
case DbcsAttribute::Trailing:
|
||||
Row.ReplaceCharacters(iCol - 1, 2, chars);
|
||||
break;
|
||||
default:
|
||||
Row.ReplaceCharacters(iCol, 1, chars);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -432,7 +504,7 @@ bool TextBuffer::InsertCharacter(const std::wstring_view chars,
|
||||
}
|
||||
|
||||
// Store color data
|
||||
fSuccess = Row.GetAttrRow().SetAttrToEnd(iCol, attr);
|
||||
fSuccess = Row.SetAttrToEnd(iCol, attr);
|
||||
if (fSuccess)
|
||||
{
|
||||
// Advance the cursor
|
||||
@@ -572,8 +644,7 @@ bool TextBuffer::IncrementCircularBuffer(const bool inVtMode)
|
||||
// the current background color, but with no meta attributes set.
|
||||
fillAttributes.SetStandardErase();
|
||||
}
|
||||
const auto fSuccess = _storage.at(_firstRow).Reset(fillAttributes);
|
||||
if (fSuccess)
|
||||
GetRowByOffset(0).Reset(fillAttributes);
|
||||
{
|
||||
// Now proceed to increment.
|
||||
// Incrementing it will cause the next line down to become the new "top" of the window (the new "0" in logical coordinates)
|
||||
@@ -585,7 +656,7 @@ bool TextBuffer::IncrementCircularBuffer(const bool inVtMode)
|
||||
_firstRow = 0;
|
||||
}
|
||||
}
|
||||
return fSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Routine Description:
|
||||
@@ -610,7 +681,7 @@ til::point TextBuffer::GetLastNonSpaceCharacter(std::optional<const Microsoft::C
|
||||
|
||||
const auto& currRow = GetRowByOffset(coordEndOfText.Y);
|
||||
// The X position of the end of the valid text is the Right draw boundary (which is one beyond the final valid character)
|
||||
coordEndOfText.X = currRow.GetCharRow().MeasureRight() - 1;
|
||||
coordEndOfText.X = currRow.MeasureRight() - 1;
|
||||
|
||||
// If the X coordinate turns out to be -1, the row was empty, we need to search backwards for the real end of text.
|
||||
const auto viewportTop = viewport.Top();
|
||||
@@ -621,7 +692,7 @@ til::point TextBuffer::GetLastNonSpaceCharacter(std::optional<const Microsoft::C
|
||||
const auto& backupRow = GetRowByOffset(coordEndOfText.Y);
|
||||
// We need to back up to the previous row if this line is empty, AND there are more rows
|
||||
|
||||
coordEndOfText.X = backupRow.GetCharRow().MeasureRight() - 1;
|
||||
coordEndOfText.X = backupRow.MeasureRight() - 1;
|
||||
fDoBackUp = (coordEndOfText.X < 0 && coordEndOfText.Y > viewportTop);
|
||||
}
|
||||
|
||||
@@ -779,10 +850,6 @@ void TextBuffer::ScrollRows(const til::CoordType firstRow, const til::CoordType
|
||||
// - end
|
||||
std::rotate(_storage.begin() + firstRow, _storage.begin() + firstRow + size, _storage.begin() + firstRow + size + delta);
|
||||
}
|
||||
|
||||
// Renumber the IDs now that we've rearranged where the rows sit within the buffer.
|
||||
// Refreshing should also delegate to the UnicodeStorage to re-key all the stored unicode sequences (where applicable).
|
||||
_RefreshRowIDs(std::nullopt);
|
||||
}
|
||||
|
||||
Cursor& TextBuffer::GetCursor() noexcept
|
||||
@@ -898,10 +965,10 @@ void TextBuffer::Reset()
|
||||
// - Success if successful. Invalid parameter if screen buffer size is unexpected. No memory if allocation failed.
|
||||
[[nodiscard]] NTSTATUS TextBuffer::ResizeTraditional(const til::size newSize) noexcept
|
||||
{
|
||||
RETURN_HR_IF(E_INVALIDARG, newSize.X < 0 || newSize.Y < 0);
|
||||
|
||||
try
|
||||
{
|
||||
BufferAllocator allocator{ newSize };
|
||||
|
||||
const auto currentSize = GetSize().Dimensions();
|
||||
const auto attributes = GetCurrentAttributes();
|
||||
|
||||
@@ -913,49 +980,30 @@ void TextBuffer::Reset()
|
||||
const auto TopRowIndex = (GetFirstRowIndex() + TopRow) % currentSize.Y;
|
||||
|
||||
// rotate rows until the top row is at index 0
|
||||
for (auto i = 0; i < TopRowIndex; i++)
|
||||
{
|
||||
_storage.emplace_back(std::move(_storage.front()));
|
||||
_storage.erase(_storage.begin());
|
||||
}
|
||||
|
||||
std::rotate(_storage.begin(), _storage.begin() + TopRowIndex, _storage.end());
|
||||
_SetFirstRowIndex(0);
|
||||
|
||||
// realloc in the Y direction
|
||||
// remove rows if we're shrinking
|
||||
while (_storage.size() > static_cast<size_t>(newSize.Y))
|
||||
{
|
||||
_storage.pop_back();
|
||||
}
|
||||
// add rows if we're growing
|
||||
while (_storage.size() < static_cast<size_t>(newSize.Y))
|
||||
{
|
||||
_storage.emplace_back(gsl::narrow_cast<til::CoordType>(_storage.size()), newSize.X, attributes, this);
|
||||
}
|
||||
_storage.resize(allocator.height());
|
||||
|
||||
// Now that we've tampered with the row placement, refresh all the row IDs.
|
||||
// Also take advantage of the row ID refresh loop to resize the rows in the X dimension
|
||||
// and cleanup the UnicodeStorage characters that might fall outside the resized buffer.
|
||||
_RefreshRowIDs(newSize.X);
|
||||
// realloc in the X direction
|
||||
for (auto& it : _storage)
|
||||
{
|
||||
it.Resize(allocator.chars(), allocator.indices(), allocator.width(), attributes);
|
||||
++allocator;
|
||||
}
|
||||
|
||||
// Update the cached size value
|
||||
_UpdateSize();
|
||||
|
||||
_charBuffer = allocator.take();
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const UnicodeStorage& TextBuffer::GetUnicodeStorage() const noexcept
|
||||
{
|
||||
return _unicodeStorage;
|
||||
}
|
||||
|
||||
UnicodeStorage& TextBuffer::GetUnicodeStorage() noexcept
|
||||
{
|
||||
return _unicodeStorage;
|
||||
}
|
||||
|
||||
void TextBuffer::SetAsActiveBuffer(const bool isActiveBuffer) noexcept
|
||||
{
|
||||
_isActiveBuffer = isActiveBuffer;
|
||||
@@ -1019,42 +1067,6 @@ void TextBuffer::TriggerNewTextNotification(const std::wstring_view newText)
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Method to help refresh all the Row IDs after manipulating the row
|
||||
// by shuffling pointers around.
|
||||
// - This will also update parent pointers that are stored in depth within the buffer
|
||||
// (e.g. it will update CharRow parents pointing at Rows that might have been moved around)
|
||||
// - Optionally takes a new row width if we're resizing to perform a resize operation and cleanup
|
||||
// any high unicode (UnicodeStorage) runs while we're already looping through the rows.
|
||||
// Arguments:
|
||||
// - newRowWidth - Optional new value for the row width.
|
||||
void TextBuffer::_RefreshRowIDs(std::optional<til::CoordType> newRowWidth)
|
||||
{
|
||||
std::unordered_map<til::CoordType, til::CoordType> rowMap;
|
||||
til::CoordType i = 0;
|
||||
for (auto& it : _storage)
|
||||
{
|
||||
// Build a map so we can update Unicode Storage
|
||||
rowMap.emplace(it.GetId(), i);
|
||||
|
||||
// Update the IDs
|
||||
it.SetId(i++);
|
||||
|
||||
// Also update the char row parent pointers as they can get shuffled up in the rotates.
|
||||
it.GetCharRow().UpdateParent(&it);
|
||||
|
||||
// Resize the rows in the X dimension if we have a new width
|
||||
if (newRowWidth.has_value())
|
||||
{
|
||||
// Realloc in the X direction
|
||||
THROW_IF_FAILED(it.Resize(newRowWidth.value()));
|
||||
}
|
||||
}
|
||||
|
||||
// Give the new mapping to Unicode Storage
|
||||
_unicodeStorage.Remap(rowMap, newRowWidth);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Retrieves the first row from the underlying buffer.
|
||||
// Arguments:
|
||||
@@ -1066,27 +1078,6 @@ ROW& TextBuffer::_GetFirstRow() noexcept
|
||||
return GetRowByOffset(0);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Retrieves the row that comes before the given row.
|
||||
// - Does not wrap around the screen buffer.
|
||||
// Arguments:
|
||||
// - The current row.
|
||||
// Return Value:
|
||||
// - reference to the previous row
|
||||
// Note:
|
||||
// - will throw exception if called with the first row of the text buffer
|
||||
ROW& TextBuffer::_GetPrevRowNoWrap(const ROW& Row)
|
||||
{
|
||||
auto prevRowIndex = Row.GetId() - 1;
|
||||
if (prevRowIndex < 0)
|
||||
{
|
||||
prevRowIndex = TotalRowCount() - 1;
|
||||
}
|
||||
|
||||
THROW_HR_IF(E_FAIL, Row.GetId() == _firstRow);
|
||||
return _storage.at(prevRowIndex);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - get delimiter class for buffer cell position
|
||||
// - used for double click selection and uia word navigation
|
||||
@@ -1095,9 +1086,9 @@ ROW& TextBuffer::_GetPrevRowNoWrap(const ROW& Row)
|
||||
// - wordDelimiters: the delimiters defined as a part of the DelimiterClass::DelimiterChar
|
||||
// Return Value:
|
||||
// - the delimiter class for the given char
|
||||
DelimiterClass TextBuffer::_GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const
|
||||
DelimiterClass TextBuffer::_GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const noexcept
|
||||
{
|
||||
return GetRowByOffset(pos.Y).GetCharRow().DelimiterClassAt(pos.X, wordDelimiters);
|
||||
return GetRowByOffset(pos.Y).DelimiterClassAt(pos.X, wordDelimiters);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1161,7 +1152,7 @@ til::point TextBuffer::GetWordStart(const til::point target, const std::wstring_
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The til::point for the first character on the current/previous READABLE "word" (inclusive)
|
||||
til::point TextBuffer::_GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const
|
||||
til::point TextBuffer::_GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const noexcept
|
||||
{
|
||||
auto result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
@@ -1206,7 +1197,7 @@ til::point TextBuffer::_GetWordStartForAccessibility(const til::point target, co
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The til::point for the first character on the current word or delimiter run (stopped by the left margin)
|
||||
til::point TextBuffer::_GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const
|
||||
til::point TextBuffer::_GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const noexcept
|
||||
{
|
||||
auto result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
@@ -1327,7 +1318,7 @@ til::point TextBuffer::_GetWordEndForAccessibility(const til::point target, cons
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The til::point for the last character of the current word or delimiter run (stopped by right margin)
|
||||
til::point TextBuffer::_GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const
|
||||
til::point TextBuffer::_GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const noexcept
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
|
||||
@@ -1362,7 +1353,7 @@ void TextBuffer::_PruneHyperlinks()
|
||||
// If the buffer does not contain the same reference, we can remove that hyperlink from our map
|
||||
// This way, obsolete hyperlink references are cleared from our hyperlink map instead of hanging around
|
||||
// Get all the hyperlink references in the row we're erasing
|
||||
const auto hyperlinks = _storage.at(_firstRow).GetAttrRow().GetHyperlinks();
|
||||
const auto hyperlinks = GetRowByOffset(0).GetHyperlinks();
|
||||
|
||||
if (!hyperlinks.empty())
|
||||
{
|
||||
@@ -1378,7 +1369,7 @@ void TextBuffer::_PruneHyperlinks()
|
||||
// to see if those references are anywhere else
|
||||
for (til::CoordType i = 1; i < total; ++i)
|
||||
{
|
||||
const auto nextRowRefs = GetRowByOffset(i).GetAttrRow().GetHyperlinks();
|
||||
const auto nextRowRefs = GetRowByOffset(i).GetHyperlinks();
|
||||
for (auto id : nextRowRefs)
|
||||
{
|
||||
if (firstRowRefs.find(id) != firstRowRefs.end())
|
||||
@@ -1472,7 +1463,7 @@ til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional<til::po
|
||||
}
|
||||
|
||||
// limit is exclusive, so we need to move back to be within valid bounds
|
||||
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing())
|
||||
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr() == DbcsAttribute::Trailing)
|
||||
{
|
||||
bufferSize.DecrementInBounds(resultPos, true);
|
||||
}
|
||||
@@ -1499,7 +1490,7 @@ til::point TextBuffer::GetGlyphEnd(const til::point pos, bool accessibilityMode,
|
||||
resultPos = limit;
|
||||
}
|
||||
|
||||
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
|
||||
if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr() == DbcsAttribute::Leading)
|
||||
{
|
||||
bufferSize.IncrementInBounds(resultPos, true);
|
||||
}
|
||||
@@ -1547,7 +1538,7 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::o
|
||||
const bool success{ ++iter };
|
||||
|
||||
// Move again if we're on a wide glyph
|
||||
if (success && iter->DbcsAttr().IsTrailing())
|
||||
if (success && iter->DbcsAttr() == DbcsAttribute::Trailing)
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
@@ -1579,7 +1570,7 @@ bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional<til::point>
|
||||
|
||||
// try to move. If we can't, we're done.
|
||||
const auto success = bufferSize.DecrementInBounds(resultPos, true);
|
||||
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading())
|
||||
if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr() == DbcsAttribute::Leading)
|
||||
{
|
||||
bufferSize.DecrementInBounds(resultPos, true);
|
||||
}
|
||||
@@ -1726,7 +1717,7 @@ void TextBuffer::_ExpandTextRow(til::inclusive_rect& textRow) const
|
||||
|
||||
// expand left side of rect
|
||||
til::point targetPoint{ textRow.Left, textRow.Top };
|
||||
if (GetCellDataAt(targetPoint)->DbcsAttr().IsTrailing())
|
||||
if (GetCellDataAt(targetPoint)->DbcsAttr() == DbcsAttribute::Trailing)
|
||||
{
|
||||
if (targetPoint.X == bufferSize.Left())
|
||||
{
|
||||
@@ -1741,7 +1732,7 @@ void TextBuffer::_ExpandTextRow(til::inclusive_rect& textRow) const
|
||||
|
||||
// expand right side of rect
|
||||
targetPoint = { textRow.Right, textRow.Bottom };
|
||||
if (GetCellDataAt(targetPoint)->DbcsAttr().IsLeading())
|
||||
if (GetCellDataAt(targetPoint)->DbcsAttr() == DbcsAttribute::Leading)
|
||||
{
|
||||
if (targetPoint.X == bufferSize.RightInclusive())
|
||||
{
|
||||
@@ -1811,7 +1802,7 @@ const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
|
||||
{
|
||||
const auto& cell = *it;
|
||||
|
||||
if (!cell.DbcsAttr().IsTrailing())
|
||||
if (cell.DbcsAttr() != DbcsAttribute::Trailing)
|
||||
{
|
||||
const auto chars = cell.Chars();
|
||||
selectionText.append(chars);
|
||||
@@ -1911,7 +1902,7 @@ std::wstring TextBuffer::GetPlainText(const til::point& start, const til::point&
|
||||
for (; it && spanLength > 0; ++it, --spanLength)
|
||||
{
|
||||
const auto& cell = *it;
|
||||
if (!cell.DbcsAttr().IsTrailing())
|
||||
if (cell.DbcsAttr() != DbcsAttribute::Trailing)
|
||||
{
|
||||
const auto chars = cell.Chars();
|
||||
text.append(chars);
|
||||
@@ -2352,12 +2343,11 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
|
||||
// Fetch the row and its "right" which is the last printable character.
|
||||
const auto& row = oldBuffer.GetRowByOffset(iOldRow);
|
||||
const auto cOldColsTotal = oldBuffer.GetLineWidth(iOldRow);
|
||||
const auto& charRow = row.GetCharRow();
|
||||
auto iRight = charRow.MeasureRight();
|
||||
auto iRight = row.MeasureRight();
|
||||
|
||||
// If we're starting a new row, try and preserve the line rendition
|
||||
// from the row in the original buffer.
|
||||
const auto newBufferPos = newBuffer.GetCursor().GetPosition();
|
||||
const auto newBufferPos = newCursor.GetPosition();
|
||||
if (newBufferPos.X == 0)
|
||||
{
|
||||
auto& newRow = newBuffer.GetRowByOffset(newBufferPos.Y);
|
||||
@@ -2404,9 +2394,9 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
|
||||
try
|
||||
{
|
||||
// TODO: MSFT: 19446208 - this should just use an iterator and the inserter...
|
||||
const auto glyph = row.GetCharRow().GlyphAt(iOldCol);
|
||||
const auto dbcsAttr = row.GetCharRow().DbcsAttrAt(iOldCol);
|
||||
const auto textAttr = row.GetAttrRow().GetAttrByColumn(iOldCol);
|
||||
const auto glyph = row.GlyphAt(iOldCol);
|
||||
const auto dbcsAttr = row.DbcsAttrAt(iOldCol);
|
||||
const auto textAttr = row.GetAttrByColumn(iOldCol);
|
||||
|
||||
if (!newBuffer.InsertCharacter(glyph, dbcsAttr, textAttr))
|
||||
{
|
||||
@@ -2450,8 +2440,8 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
|
||||
try
|
||||
{
|
||||
// TODO: MSFT: 19446208 - this should just use an iterator and the inserter...
|
||||
const auto textAttr = row.GetAttrRow().GetAttrByColumn(copyAttrCol);
|
||||
if (!newRow.GetAttrRow().SetAttrToEnd(newAttrColumn, textAttr))
|
||||
const auto textAttr = row.GetAttrByColumn(copyAttrCol);
|
||||
if (!newRow.SetAttrToEnd(newAttrColumn, textAttr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2565,8 +2555,7 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
|
||||
// the last attr when wider.
|
||||
auto& newRow = newBuffer.GetRowByOffset(newRowY);
|
||||
const auto newWidth = newBuffer.GetLineWidth(newRowY);
|
||||
newRow.GetAttrRow() = row.GetAttrRow();
|
||||
newRow.GetAttrRow().Resize(newWidth);
|
||||
newRow.TransferAttributes(row.Attributes(), newWidth);
|
||||
|
||||
newRowY++;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ filling in the last row, and updating the screen.
|
||||
#include "cursor.h"
|
||||
#include "Row.hpp"
|
||||
#include "TextAttribute.hpp"
|
||||
#include "UnicodeStorage.hpp"
|
||||
#include "../types/inc/Viewport.hpp"
|
||||
|
||||
#include "../buffer/out/textBufferCellIterator.hpp"
|
||||
@@ -140,9 +139,6 @@ public:
|
||||
|
||||
[[nodiscard]] HRESULT ResizeTraditional(const til::size newSize) noexcept;
|
||||
|
||||
const UnicodeStorage& GetUnicodeStorage() const noexcept;
|
||||
UnicodeStorage& GetUnicodeStorage() noexcept;
|
||||
|
||||
void SetAsActiveBuffer(const bool isActiveBuffer) noexcept;
|
||||
bool IsActiveBuffer() const noexcept;
|
||||
|
||||
@@ -221,54 +217,42 @@ public:
|
||||
|
||||
private:
|
||||
void _UpdateSize();
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
std::vector<ROW> _storage;
|
||||
Cursor _cursor;
|
||||
|
||||
til::CoordType _firstRow; // indexes top row (not necessarily 0)
|
||||
|
||||
TextAttribute _currentAttributes;
|
||||
|
||||
// storage location for glyphs that can't fit into the buffer normally
|
||||
UnicodeStorage _unicodeStorage;
|
||||
|
||||
bool _isActiveBuffer;
|
||||
Microsoft::Console::Render::Renderer& _renderer;
|
||||
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
|
||||
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
|
||||
uint16_t _currentHyperlinkId;
|
||||
|
||||
void _RefreshRowIDs(std::optional<til::CoordType> newRowWidth);
|
||||
|
||||
void _SetFirstRowIndex(const til::CoordType FirstRowIndex) noexcept;
|
||||
|
||||
til::point _GetPreviousFromCursor() const noexcept;
|
||||
|
||||
void _SetWrapOnCurrentRow() noexcept;
|
||||
void _AdjustWrapOnCurrentRow(const bool fSet) noexcept;
|
||||
|
||||
// Assist with maintaining proper buffer state for Double Byte character sequences
|
||||
bool _PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
bool _AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribute);
|
||||
|
||||
ROW& _GetFirstRow() noexcept;
|
||||
ROW& _GetPrevRowNoWrap(const ROW& row);
|
||||
|
||||
void _ExpandTextRow(til::inclusive_rect& selectionRow) const;
|
||||
|
||||
DelimiterClass _GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
DelimiterClass _GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const noexcept;
|
||||
til::point _GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const noexcept;
|
||||
til::point _GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const noexcept;
|
||||
til::point _GetWordEndForAccessibility(const til::point target, const std::wstring_view wordDelimiters, const til::point limit) const;
|
||||
til::point _GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
|
||||
til::point _GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const noexcept;
|
||||
void _PruneHyperlinks();
|
||||
|
||||
static void _AppendRTFText(std::ostringstream& contentBuilder, const std::wstring_view& text);
|
||||
|
||||
Microsoft::Console::Render::Renderer& _renderer;
|
||||
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
|
||||
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
|
||||
uint16_t _currentHyperlinkId = 1;
|
||||
|
||||
std::unordered_map<size_t, std::wstring> _idsAndPatterns;
|
||||
size_t _currentPatternId;
|
||||
size_t _currentPatternId = 0;
|
||||
|
||||
wil::unique_virtualalloc_ptr<std::byte> _charBuffer;
|
||||
std::vector<ROW> _storage;
|
||||
TextAttribute _currentAttributes;
|
||||
til::CoordType _firstRow = 0; // indexes top row (not necessarily 0)
|
||||
|
||||
Cursor _cursor;
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
|
||||
bool _isActiveBuffer = false;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TextBufferTests;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "textBufferCellIterator.hpp"
|
||||
|
||||
#include "CharRow.hpp"
|
||||
#include "textBuffer.hpp"
|
||||
#include "../types/inc/convert.hpp"
|
||||
#include "../types/inc/viewport.hpp"
|
||||
@@ -37,7 +36,7 @@ TextBufferCellIterator::TextBufferCellIterator(const TextBuffer& buffer, til::po
|
||||
_bounds(limits),
|
||||
_exceeded(false),
|
||||
_view({}, {}, {}, TextAttributeBehavior::Stored),
|
||||
_attrIter(s_GetRow(buffer, pos)->GetAttrRow().cbegin())
|
||||
_attrIter(s_GetRow(buffer, pos)->AttrBegin())
|
||||
{
|
||||
// Throw if the bounds rectangle is not limited to the inside of the given buffer.
|
||||
THROW_HR_IF(E_INVALIDARG, !buffer.GetSize().IsInBounds(limits));
|
||||
@@ -165,16 +164,15 @@ TextBufferCellIterator& TextBufferCellIterator::operator+=(const ptrdiff_t& move
|
||||
_attrIter += diff;
|
||||
_view.UpdateTextAttribute(*_attrIter);
|
||||
|
||||
const auto& charRow = _pRow->GetCharRow();
|
||||
_view.UpdateText(charRow.GlyphAt(newX));
|
||||
_view.UpdateDbcsAttribute(charRow.DbcsAttrAt(newX));
|
||||
_view.UpdateText(_pRow->GlyphAt(newX));
|
||||
_view.UpdateDbcsAttribute(_pRow->DbcsAttrAt(newX));
|
||||
_pos.X = newX;
|
||||
}
|
||||
else
|
||||
{
|
||||
// cold path (_GenerateView is slow)
|
||||
_pRow = s_GetRow(_buffer, { newX, newY });
|
||||
_attrIter = _pRow->GetAttrRow().cbegin() + newX;
|
||||
_attrIter = _pRow->AttrBegin() + newX;
|
||||
_pos.X = newX;
|
||||
_pos.Y = newY;
|
||||
_GenerateView();
|
||||
@@ -289,12 +287,12 @@ ptrdiff_t TextBufferCellIterator::operator-(const TextBufferCellIterator& it)
|
||||
// - Sets the coordinate position that this iterator will inspect within the text buffer on dereference.
|
||||
// Arguments:
|
||||
// - newPos - The new coordinate position.
|
||||
void TextBufferCellIterator::_SetPos(const til::point newPos)
|
||||
void TextBufferCellIterator::_SetPos(const til::point newPos) noexcept
|
||||
{
|
||||
if (newPos.Y != _pos.Y)
|
||||
{
|
||||
_pRow = s_GetRow(_buffer, newPos);
|
||||
_attrIter = _pRow->GetAttrRow().cbegin();
|
||||
_attrIter = _pRow->AttrBegin();
|
||||
_pos.X = 0;
|
||||
}
|
||||
|
||||
@@ -324,10 +322,10 @@ const ROW* TextBufferCellIterator::s_GetRow(const TextBuffer& buffer, const til:
|
||||
|
||||
// Routine Description:
|
||||
// - Updates the internal view. Call after updating row, attribute, or positions.
|
||||
void TextBufferCellIterator::_GenerateView()
|
||||
void TextBufferCellIterator::_GenerateView() noexcept
|
||||
{
|
||||
_view = OutputCellView(_pRow->GetCharRow().GlyphAt(_pos.X),
|
||||
_pRow->GetCharRow().DbcsAttrAt(_pos.X),
|
||||
_view = OutputCellView(_pRow->GlyphAt(_pos.X),
|
||||
_pRow->DbcsAttrAt(_pos.X),
|
||||
*_attrIter,
|
||||
TextAttributeBehavior::Stored);
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ Author(s):
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CharRow.hpp"
|
||||
#include "AttrRow.hpp"
|
||||
#include "Row.hpp"
|
||||
#include "OutputCellView.hpp"
|
||||
#include "../../types/inc/viewport.hpp"
|
||||
|
||||
@@ -50,14 +49,14 @@ public:
|
||||
til::point Pos() const noexcept;
|
||||
|
||||
protected:
|
||||
void _SetPos(const til::point newPos);
|
||||
void _GenerateView();
|
||||
void _SetPos(const til::point newPos) noexcept;
|
||||
void _GenerateView() noexcept;
|
||||
static const ROW* s_GetRow(const TextBuffer& buffer, const til::point pos) noexcept;
|
||||
|
||||
til::small_rle<TextAttribute, uint16_t, 1>::const_iterator _attrIter;
|
||||
OutputCellView _view;
|
||||
|
||||
const ROW* _pRow;
|
||||
ATTR_ROW::const_iterator _attrIter;
|
||||
const TextBuffer& _buffer;
|
||||
const Microsoft::Console::Types::Viewport _bounds;
|
||||
bool _exceeded;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "textBufferTextIterator.hpp"
|
||||
|
||||
#include "CharRow.hpp"
|
||||
#include "Row.hpp"
|
||||
|
||||
#pragma hdrstop
|
||||
|
||||
@@ -683,7 +683,7 @@ namespace
|
||||
{
|
||||
STDMETHODIMP Advance(IDataRow** ppDataRow) override
|
||||
{
|
||||
if (_index < std::extent<decltype(testCases)>::value)
|
||||
if (_index < std::extent_v<decltype(testCases)>)
|
||||
{
|
||||
Microsoft::WRL::MakeAndInitialize<ArrayIndexTaefAdapterRow>(ppDataRow, _index++);
|
||||
}
|
||||
@@ -737,34 +737,22 @@ class ReflowTests
|
||||
{
|
||||
auto buffer = std::make_unique<TextBuffer>(testBuffer.size, TextAttribute{ 0x7 }, 0, false, renderer);
|
||||
|
||||
til::CoordType i{};
|
||||
til::CoordType y = 0;
|
||||
for (const auto& testRow : testBuffer.rows)
|
||||
{
|
||||
auto& row{ buffer->GetRowByOffset(i) };
|
||||
auto& row{ buffer->GetRowByOffset(y) };
|
||||
|
||||
auto& charRow{ row.GetCharRow() };
|
||||
row.SetWrapForced(testRow.wrap);
|
||||
|
||||
til::CoordType j{};
|
||||
for (auto it{ charRow.begin() }; it != charRow.end(); ++it)
|
||||
til::CoordType x = 0;
|
||||
for (const auto& ch : testRow.text)
|
||||
{
|
||||
// Yes, we're about to manually create a buffer. It is unpleasant.
|
||||
const auto ch{ til::at(testRow.text, j) };
|
||||
it->Char() = ch;
|
||||
if (IsGlyphFullWidth(ch))
|
||||
{
|
||||
it->DbcsAttr().SetLeading();
|
||||
it++;
|
||||
it->Char() = ch;
|
||||
it->DbcsAttr().SetTrailing();
|
||||
}
|
||||
else
|
||||
{
|
||||
it->DbcsAttr().SetSingle();
|
||||
}
|
||||
j++;
|
||||
const til::CoordType width = IsGlyphFullWidth(ch) ? 2 : 1;
|
||||
row.ReplaceCharacters(x, width, { &ch, 1 });
|
||||
x += width;
|
||||
}
|
||||
i++;
|
||||
|
||||
y++;
|
||||
}
|
||||
|
||||
buffer->GetCursor().SetPosition(testBuffer.cursor);
|
||||
@@ -783,42 +771,44 @@ class ReflowTests
|
||||
VERIFY_ARE_EQUAL(testBuffer.cursor, buffer.GetCursor().GetPosition());
|
||||
VERIFY_ARE_EQUAL(testBuffer.size, buffer.GetSize().Dimensions());
|
||||
|
||||
til::CoordType i{};
|
||||
til::CoordType y = 0;
|
||||
for (const auto& testRow : testBuffer.rows)
|
||||
{
|
||||
NoThrowString indexString;
|
||||
const auto& row{ buffer.GetRowByOffset(i) };
|
||||
const auto& row{ buffer.GetRowByOffset(y) };
|
||||
|
||||
const auto& charRow{ row.GetCharRow() };
|
||||
|
||||
indexString.Format(L"[Row %d]", i);
|
||||
indexString.Format(L"[Row %d]", y);
|
||||
VERIFY_ARE_EQUAL(testRow.wrap, row.WasWrapForced(), indexString);
|
||||
|
||||
til::CoordType j{};
|
||||
for (auto it{ charRow.begin() }; it != charRow.end(); ++it)
|
||||
til::CoordType x = 0;
|
||||
til::CoordType j = 0;
|
||||
for (const auto& ch : testRow.text)
|
||||
{
|
||||
indexString.Format(L"[Cell %d, %d; Text line index %d]", it - charRow.begin(), i, j);
|
||||
// Yes, we're about to manually create a buffer. It is unpleasant.
|
||||
const auto ch{ til::at(testRow.text, j) };
|
||||
indexString.Format(L"[Cell %d, %d; Text line index %d]", x, y, j);
|
||||
|
||||
if (IsGlyphFullWidth(ch))
|
||||
{
|
||||
// Char is full width in test buffer, so
|
||||
// ensure that real buffer is LEAD, TRAIL (ch)
|
||||
VERIFY_IS_TRUE(it->DbcsAttr().IsLeading(), indexString);
|
||||
VERIFY_ARE_EQUAL(ch, it->Char(), indexString);
|
||||
VERIFY_ARE_EQUAL(row.DbcsAttrAt(x), DbcsAttribute::Leading, indexString);
|
||||
VERIFY_ARE_EQUAL(ch, row.GlyphAt(x).front(), indexString);
|
||||
++x;
|
||||
|
||||
it++;
|
||||
VERIFY_IS_TRUE(it->DbcsAttr().IsTrailing(), indexString);
|
||||
VERIFY_ARE_EQUAL(row.DbcsAttrAt(x), DbcsAttribute::Trailing, indexString);
|
||||
VERIFY_ARE_EQUAL(ch, row.GlyphAt(x).front(), indexString);
|
||||
++x;
|
||||
}
|
||||
else
|
||||
{
|
||||
VERIFY_IS_TRUE(it->DbcsAttr().IsSingle(), indexString);
|
||||
VERIFY_ARE_EQUAL(row.DbcsAttrAt(x), DbcsAttribute::Single, indexString);
|
||||
VERIFY_ARE_EQUAL(ch, row.GlyphAt(x).front(), indexString);
|
||||
++x;
|
||||
}
|
||||
|
||||
VERIFY_ARE_EQUAL(ch, it->Char(), indexString);
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ void TextAttributeTests::TestRoundtripMetaBits()
|
||||
auto attr = TextAttribute(expectedLegacy);
|
||||
VERIFY_IS_TRUE(attr.IsLegacy());
|
||||
VERIFY_ARE_EQUAL(expectedLegacy, attr.GetLegacyAttributes());
|
||||
VERIFY_ARE_EQUAL(flag, attr._wAttrLegacy);
|
||||
VERIFY_ARE_EQUAL(flag, static_cast<WORD>(attr._attrs));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
<ClCompile Include="ReflowTests.cpp" />
|
||||
<ClCompile Include="TextColorTests.cpp" />
|
||||
<ClCompile Include="TextAttributeTests.cpp" />
|
||||
<ClCompile Include="UnicodeStorageTests.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -42,4 +41,4 @@
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
<Import Project="$(SolutionDir)src\common.build.tests.props" />
|
||||
<Import Project="$(SolutionDir)src\common.nugetversions.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "WexTestClass.h"
|
||||
#include "../../inc/consoletaeftemplates.hpp"
|
||||
|
||||
#include "../UnicodeStorage.hpp"
|
||||
|
||||
using namespace WEX::Common;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
|
||||
class UnicodeStorageTests
|
||||
{
|
||||
TEST_CLASS(UnicodeStorageTests);
|
||||
|
||||
TEST_METHOD(CanOverwriteEmoji)
|
||||
{
|
||||
UnicodeStorage storage;
|
||||
const til::point coord{ 1, 3 };
|
||||
const std::vector<wchar_t> newMoon{ 0xD83C, 0xDF11 };
|
||||
const std::vector<wchar_t> fullMoon{ 0xD83C, 0xDF15 };
|
||||
|
||||
// store initial glyph
|
||||
storage.StoreGlyph(coord, newMoon);
|
||||
|
||||
// verify it was stored
|
||||
auto findIt = storage._map.find(coord);
|
||||
VERIFY_ARE_NOT_EQUAL(findIt, storage._map.end());
|
||||
const auto& newMoonGlyph = findIt->second;
|
||||
VERIFY_ARE_EQUAL(newMoonGlyph.size(), newMoon.size());
|
||||
for (size_t i = 0; i < newMoon.size(); ++i)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(newMoonGlyph.at(i), newMoon.at(i));
|
||||
}
|
||||
|
||||
// overwrite it
|
||||
storage.StoreGlyph(coord, fullMoon);
|
||||
|
||||
// verify the glyph was overwritten
|
||||
findIt = storage._map.find(coord);
|
||||
VERIFY_ARE_NOT_EQUAL(findIt, storage._map.end());
|
||||
const auto& fullMoonGlyph = findIt->second;
|
||||
VERIFY_ARE_EQUAL(fullMoonGlyph.size(), fullMoon.size());
|
||||
for (size_t i = 0; i < fullMoon.size(); ++i)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(fullMoonGlyph.at(i), fullMoon.at(i));
|
||||
}
|
||||
}
|
||||
};
|
||||
3
src/buffer/out/ut_textbuffer/sources.dep
Normal file
3
src/buffer/out/ut_textbuffer/sources.dep
Normal file
@@ -0,0 +1,3 @@
|
||||
BUILD_PASS1_CONSUMES= \
|
||||
onecore\windows\vcpkg|PASS1 \
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22000.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22000.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22000.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
@@ -188,8 +188,8 @@
|
||||
<com:ComInterface>
|
||||
<com:ProxyStub Id="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F" DisplayName="OpenConsoleHandoffProxy" Path="OpenConsoleProxy.dll"/>
|
||||
<com:Interface Id="E686C757-9A35-4A1C-B3CE-0BCC8B5C69F4" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/> <!-- ITerminalHandoff -->
|
||||
<com:Interface Id="AA6B364F-4A50-4176-9002-0AE755E7B5EF" ProxyStubClsid="1833E661-CC81-4DD0-87C6-C2F74BD39EFA"/> <!-- ITerminalHandoff2 -->
|
||||
<com:Interface Id="59D55CCE-FC8A-48B4-ACE8-0A9286C6557F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/> <!-- ITerminalHandoff -->
|
||||
<com:Interface Id="AA6B364F-4A50-4176-9002-0AE755E7B5EF" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/> <!-- ITerminalHandoff2 -->
|
||||
<com:Interface Id="746E6BC0-AB05-4E38-AB14-71E86763141F" ProxyStubClsid="3171DE52-6EFA-4AEF-8A9F-D02BD67E7A4F"/>
|
||||
</com:ComInterface>
|
||||
</com:Extension>
|
||||
|
||||
@@ -41,11 +41,13 @@ Author(s):
|
||||
#include <winrt/Windows.system.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <Windows.Graphics.Imaging.Interop.h>
|
||||
#include <winrt/windows.ui.core.h>
|
||||
#include <winrt/Windows.ui.input.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Windows.ui.xaml.media.h>
|
||||
#include <winrt/Windows.UI.Xaml.Media.Imaging.h>
|
||||
#include <winrt/Windows.ui.xaml.input.h>
|
||||
#include <winrt/Windows.UI.Xaml.Markup.h>
|
||||
#include <winrt/Windows.UI.Xaml.Documents.h>
|
||||
|
||||
@@ -503,7 +503,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
@@ -521,7 +521,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash"));
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
@@ -843,7 +843,7 @@ namespace TerminalAppLocalTests
|
||||
// | 1 | 2 |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Right, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
secondId = tab->_activePane->Id().value();
|
||||
});
|
||||
Sleep(250);
|
||||
@@ -861,7 +861,7 @@ namespace TerminalAppLocalTests
|
||||
// | 3 | |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
// Split again to make the 3rd tab
|
||||
thirdId = tab->_activePane->Id().value();
|
||||
@@ -881,7 +881,7 @@ namespace TerminalAppLocalTests
|
||||
// | 3 | 4 |
|
||||
// | | |
|
||||
// -------------------
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, true, nullptr));
|
||||
page->_SplitPane(SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
fourthId = tab->_activePane->Id().value();
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.22000.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.22621.0" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug" MinVersion="14.0.27023.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.Debug.UWPDesktop" MinVersion="14.0.27027.1" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
</Dependencies>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<uap:SupportedUsers>multiple</uap:SupportedUsers>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.22000.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
<Resources>
|
||||
<Resource Language="x-generate" />
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "HwndTerminal.hpp"
|
||||
#include <windowsx.h>
|
||||
#include "../../types/TermControlUiaProvider.hpp"
|
||||
#include <DefaultSettings.h>
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include "../../types/viewport.cpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
@@ -54,6 +50,17 @@ LRESULT CALLBACK HwndTerminal::HwndTerminalWndProc(
|
||||
LPARAM lParam) noexcept
|
||||
try
|
||||
{
|
||||
if (WM_NCCREATE == uMsg)
|
||||
{
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
auto cs = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
HwndTerminal* that = static_cast<HwndTerminal*>(cs->lpCreateParams);
|
||||
that->_hwnd = wil::unique_hwnd(hwnd);
|
||||
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(that));
|
||||
return DefWindowProc(hwnd, WM_NCCREATE, wParam, lParam);
|
||||
}
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
auto terminal = reinterpret_cast<HwndTerminal*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
|
||||
@@ -169,7 +176,7 @@ static bool RegisterTermClass(HINSTANCE hInstance) noexcept
|
||||
}
|
||||
|
||||
HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8 },
|
||||
_desiredFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, 14, CP_UTF8 },
|
||||
_actualFont{ L"Consolas", 0, DEFAULT_FONT_WEIGHT, { 0, 14 }, CP_UTF8, false },
|
||||
_uiaProvider{ nullptr },
|
||||
_currentDpi{ USER_DEFAULT_SCREEN_DPI },
|
||||
@@ -182,7 +189,7 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
|
||||
if (RegisterTermClass(hInstance))
|
||||
{
|
||||
_hwnd = wil::unique_hwnd(CreateWindowExW(
|
||||
CreateWindowExW(
|
||||
0,
|
||||
term_window_class,
|
||||
nullptr,
|
||||
@@ -197,10 +204,7 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
|
||||
parentHwnd,
|
||||
nullptr,
|
||||
hInstance,
|
||||
nullptr));
|
||||
|
||||
#pragma warning(suppress : 26490) // Win32 APIs can only store void*, have to use reinterpret_cast
|
||||
SetWindowLongPtr(_hwnd.get(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,14 +328,15 @@ IRawElementProviderSimple* HwndTerminal::_GetUiaProvider() noexcept
|
||||
{
|
||||
// If TermControlUiaProvider throws during construction,
|
||||
// we don't want to try constructing an instance again and again.
|
||||
// _uiaProviderInitialized helps us prevent this.
|
||||
if (!_uiaProviderInitialized)
|
||||
if (!_uiaProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto lock = _terminal->LockForWriting();
|
||||
LOG_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<::Microsoft::Terminal::TermControlUiaProvider>(&_uiaProvider, this->GetUiaData(), this));
|
||||
_uiaProviderInitialized = true;
|
||||
LOG_IF_FAILED(::Microsoft::WRL::MakeAndInitialize<HwndTerminalAutomationPeer>(&_uiaProvider, this->GetUiaData(), this));
|
||||
_uiaEngine = std::make_unique<::Microsoft::Console::Render::UiaEngine>(_uiaProvider.Get());
|
||||
LOG_IF_FAILED(_uiaEngine->Enable());
|
||||
_renderer->AddRenderEngine(_uiaEngine.get());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -380,29 +385,10 @@ void HwndTerminal::SendOutput(std::wstring_view data)
|
||||
|
||||
HRESULT _stdcall CreateTerminal(HWND parentHwnd, _Out_ void** hwnd, _Out_ void** terminal)
|
||||
{
|
||||
// In order for UIA to hook up properly there needs to be a "static" window hosting the
|
||||
// inner win32 control. If the static window is not present then WM_GETOBJECT messages
|
||||
// will not reach the child control, and the uia element will not be present in the tree.
|
||||
auto _hostWindow = CreateWindowEx(
|
||||
0,
|
||||
L"static",
|
||||
nullptr,
|
||||
WS_CHILD |
|
||||
WS_CLIPCHILDREN |
|
||||
WS_CLIPSIBLINGS |
|
||||
WS_VISIBLE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
parentHwnd,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
auto _terminal = std::make_unique<HwndTerminal>(_hostWindow);
|
||||
auto _terminal = std::make_unique<HwndTerminal>(parentHwnd);
|
||||
RETURN_IF_FAILED(_terminal->Initialize());
|
||||
|
||||
*hwnd = _hostWindow;
|
||||
*hwnd = _terminal->GetHwnd();
|
||||
*terminal = _terminal.release();
|
||||
|
||||
return S_OK;
|
||||
@@ -725,6 +711,10 @@ try
|
||||
{
|
||||
modifiers |= ControlKeyStates::EnhancedKey;
|
||||
}
|
||||
if (vkey && keyDown && _uiaProvider)
|
||||
{
|
||||
_uiaProvider->RecordKeyEvent(vkey);
|
||||
}
|
||||
_terminal->SendKeyEvent(vkey, scanCode, modifiers, keyDown);
|
||||
}
|
||||
CATCH_LOG();
|
||||
@@ -799,7 +789,7 @@ void _stdcall TerminalSetTheme(void* terminal, TerminalTheme theme, LPCWSTR font
|
||||
|
||||
publicTerminal->_terminal->SetCursorStyle(static_cast<DispatchTypes::CursorStyle>(theme.CursorStyle));
|
||||
|
||||
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, { 0, fontSize }, CP_UTF8 };
|
||||
publicTerminal->_desiredFont = { fontFamily, 0, DEFAULT_FONT_WEIGHT, static_cast<float>(fontSize), CP_UTF8 };
|
||||
publicTerminal->_UpdateFont(newDpi);
|
||||
|
||||
// When the font changes the terminal dimensions need to be recalculated since the available row and column
|
||||
@@ -833,12 +823,20 @@ void __stdcall TerminalSetFocus(void* terminal)
|
||||
{
|
||||
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
|
||||
publicTerminal->_focused = true;
|
||||
if (auto uiaEngine = publicTerminal->_uiaEngine.get())
|
||||
{
|
||||
LOG_IF_FAILED(uiaEngine->Enable());
|
||||
}
|
||||
}
|
||||
|
||||
void __stdcall TerminalKillFocus(void* terminal)
|
||||
{
|
||||
auto publicTerminal = static_cast<HwndTerminal*>(terminal);
|
||||
publicTerminal->_focused = false;
|
||||
if (auto uiaEngine = publicTerminal->_uiaEngine.get())
|
||||
{
|
||||
LOG_IF_FAILED(uiaEngine->Disable());
|
||||
}
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
#include "../../renderer/base/Renderer.hpp"
|
||||
#include "../../renderer/dx/DxRenderer.hpp"
|
||||
#include "../../renderer/uia/UiaRenderer.hpp"
|
||||
#include "../../cascadia/TerminalCore/Terminal.hpp"
|
||||
#include <UIAutomationCore.h>
|
||||
#include "../../types/IControlAccessibilityInfo.h"
|
||||
#include "../../types/TermControlUiaProvider.hpp"
|
||||
#include "HwndTerminalAutomationPeer.hpp"
|
||||
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
||||
@@ -74,15 +74,15 @@ private:
|
||||
FontInfo _actualFont;
|
||||
int _currentDpi;
|
||||
std::function<void(wchar_t*)> _pfnWriteCallback;
|
||||
::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider;
|
||||
::Microsoft::WRL::ComPtr<HwndTerminalAutomationPeer> _uiaProvider;
|
||||
|
||||
std::unique_ptr<::Microsoft::Terminal::Core::Terminal> _terminal;
|
||||
|
||||
std::unique_ptr<::Microsoft::Console::Render::Renderer> _renderer;
|
||||
std::unique_ptr<::Microsoft::Console::Render::DxEngine> _renderEngine;
|
||||
std::unique_ptr<::Microsoft::Console::Render::UiaEngine> _uiaEngine;
|
||||
|
||||
bool _focused{ false };
|
||||
bool _uiaProviderInitialized{ false };
|
||||
|
||||
std::chrono::milliseconds _multiClickTime;
|
||||
unsigned int _multiClickCounter{};
|
||||
|
||||
159
src/cascadia/PublicTerminalCore/HwndTerminalAutomationPeer.cpp
Normal file
159
src/cascadia/PublicTerminalCore/HwndTerminalAutomationPeer.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "HwndTerminalAutomationPeer.hpp"
|
||||
#include "../../types/UiaTracing.h"
|
||||
#include <UIAutomationCoreApi.h>
|
||||
|
||||
#pragma warning(suppress : 4471) // We don't control UIAutomationClient
|
||||
#include <UIAutomationClient.h>
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
|
||||
static constexpr wchar_t UNICODE_NEWLINE{ L'\n' };
|
||||
|
||||
// Method Description:
|
||||
// - creates a copy of the provided text with all of the control characters removed
|
||||
// Arguments:
|
||||
// - text: the string we're sanitizing
|
||||
// Return Value:
|
||||
// - a copy of "sanitized" with all of the control characters removed
|
||||
static std::wstring Sanitize(std::wstring_view text)
|
||||
{
|
||||
std::wstring sanitized{ text };
|
||||
sanitized.erase(std::remove_if(sanitized.begin(), sanitized.end(), [](wchar_t c) {
|
||||
return (c < UNICODE_SPACE && c != UNICODE_NEWLINE) || c == 0x7F /*DEL*/;
|
||||
}),
|
||||
sanitized.end());
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - verifies if a given string has text that would be read by a screen reader.
|
||||
// - a string of control characters, for example, would not be read.
|
||||
// Arguments:
|
||||
// - text: the string we're validating
|
||||
// Return Value:
|
||||
// - true, if the text is readable. false, otherwise.
|
||||
static constexpr bool IsReadable(std::wstring_view text)
|
||||
{
|
||||
for (const auto c : text)
|
||||
{
|
||||
if (c > UNICODE_SPACE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HwndTerminalAutomationPeer::RecordKeyEvent(const WORD vkey)
|
||||
{
|
||||
if (const auto charCode{ MapVirtualKey(vkey, MAPVK_VK_TO_CHAR) })
|
||||
{
|
||||
if (const auto keyEventChar{ gsl::narrow_cast<wchar_t>(charCode) }; IsReadable({ &keyEventChar, 1 }))
|
||||
{
|
||||
_keyEvents.emplace_back(keyEventChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of IRawElementProviderSimple::get_PropertyValue.
|
||||
// Gets custom properties.
|
||||
IFACEMETHODIMP HwndTerminalAutomationPeer::GetPropertyValue(_In_ PROPERTYID propertyId,
|
||||
_Out_ VARIANT* pVariant) noexcept
|
||||
{
|
||||
pVariant->vt = VT_EMPTY;
|
||||
|
||||
// Returning the default will leave the property as the default
|
||||
// so we only really need to touch it for the properties we want to implement
|
||||
if (propertyId == UIA_ClassNamePropertyId)
|
||||
{
|
||||
// IMPORTANT: Do NOT change the name. Screen readers like may be dependent on this being "WpfTermControl".
|
||||
pVariant->bstrVal = SysAllocString(L"WPFTermControl");
|
||||
if (pVariant->bstrVal != nullptr)
|
||||
{
|
||||
pVariant->vt = VT_BSTR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// fall back to shared implementation
|
||||
return TermControlUiaProvider::GetPropertyValue(propertyId, pVariant);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the terminal's selection has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalSelectionChanged()
|
||||
{
|
||||
UiaTracing::Signal::SelectionChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextSelectionChangedEventId));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the terminal's output has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalTextChanged()
|
||||
{
|
||||
UiaTracing::Signal::TextChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextChangedEventId));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Signals the ui automation client that the cursor's state has changed and should be updated
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void HwndTerminalAutomationPeer::SignalCursorChanged()
|
||||
{
|
||||
UiaTracing::Signal::CursorChanged();
|
||||
LOG_IF_FAILED(UiaRaiseAutomationEvent(this, UIA_Text_TextSelectionChangedEventId));
|
||||
}
|
||||
|
||||
void HwndTerminalAutomationPeer::NotifyNewOutput(std::wstring_view newOutput)
|
||||
{
|
||||
// Try to suppress any events (or event data)
|
||||
// that is just the keypress the user made
|
||||
auto sanitized{ Sanitize(newOutput) };
|
||||
while (!_keyEvents.empty() && IsReadable(sanitized))
|
||||
{
|
||||
if (til::toupper_ascii(sanitized.front()) == _keyEvents.front())
|
||||
{
|
||||
// the key event's character (i.e. the "A" key) matches
|
||||
// the output character (i.e. "a" or "A" text).
|
||||
// We can assume that the output character resulted from
|
||||
// the pressed key, so we can ignore it.
|
||||
sanitized = sanitized.substr(1);
|
||||
_keyEvents.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The output doesn't match,
|
||||
// so clear the input stack and
|
||||
// move on to fire the event.
|
||||
_keyEvents.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress event if the remaining text is not readable
|
||||
if (!IsReadable(sanitized))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sanitizedBstr = wil::make_bstr_nothrow(sanitized.c_str());
|
||||
static auto activityId = wil::make_bstr_nothrow(L"TerminalTextOutput");
|
||||
LOG_IF_FAILED(UiaRaiseNotificationEvent(this, NotificationKind_ActionCompleted, NotificationProcessing_All, sanitizedBstr.get(), activityId.get()));
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- HwndTerminalAutomationPeer.hpp
|
||||
|
||||
Abstract:
|
||||
- This module provides UI Automation access to the HwndTerminal
|
||||
to support both automation tests and accessibility (screen
|
||||
reading) applications. This mainly interacts with TermControlUiaProvider
|
||||
to allow for shared code with Windows Terminal accessibility providers.
|
||||
|
||||
Author(s):
|
||||
- Carlos Zamora (CaZamor) 2022
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../types/TermControlUiaProvider.hpp"
|
||||
#include "../types/IUiaEventDispatcher.h"
|
||||
#include "../types/IControlAccessibilityInfo.h"
|
||||
|
||||
class HwndTerminalAutomationPeer :
|
||||
public ::Microsoft::Console::Types::IUiaEventDispatcher,
|
||||
public ::Microsoft::Terminal::TermControlUiaProvider
|
||||
{
|
||||
public:
|
||||
void RecordKeyEvent(const WORD vkey);
|
||||
|
||||
IFACEMETHODIMP GetPropertyValue(_In_ PROPERTYID idProp,
|
||||
_Out_ VARIANT* pVariant) noexcept override;
|
||||
|
||||
#pragma region IUiaEventDispatcher
|
||||
void SignalSelectionChanged() override;
|
||||
void SignalTextChanged() override;
|
||||
void SignalCursorChanged() override;
|
||||
void NotifyNewOutput(std::wstring_view newOutput) override;
|
||||
#pragma endregion
|
||||
private:
|
||||
std::deque<wchar_t> _keyEvents;
|
||||
};
|
||||
@@ -15,9 +15,11 @@
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HwndTerminal.cpp" />
|
||||
<ClCompile Include="HwndTerminalAutomationPeer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="HwndTerminal.hpp" />
|
||||
<ClInclude Include="HwndTerminalAutomationPeer.hpp" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -39,6 +41,9 @@
|
||||
<ProjectReference Include="$(SolutionDir)src\renderer\dx\lib\dx.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj">
|
||||
<Project>{48d21369-3d7b-4431-9967-24e81292cf63}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
@@ -55,4 +60,4 @@
|
||||
<AdditionalDependencies>Uiautomationcore.lib;onecoreuap.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -24,6 +24,9 @@
|
||||
<ClCompile Include="HwndTerminal.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HwndTerminalAutomationPeer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
@@ -32,5 +35,8 @@
|
||||
<ClInclude Include="HwndTerminal.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HwndTerminalAutomationPeer.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user