Compare commits

...

2 Commits

Author SHA1 Message Date
Dustin L. Howett
e7131daa4d Migrate spelling-0.0.21 changes from main 2022-08-01 21:47:15 +02:00
Leonard Hecker
65f0200842 wip 2022-08-01 21:47:15 +02:00
53 changed files with 1278 additions and 1243 deletions

View File

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

View File

@@ -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).

View File

@@ -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,9 +56,11 @@ Llast
llvm
Lmid
locl
lol
lorem
Lorigin
maxed
minimalistic
mkmk
mnt
mru
@@ -80,6 +84,7 @@ runtimes
shcha
slnt
Sos
ssh
timeline
timelines
timestamped
@@ -88,6 +93,7 @@ tokenizes
tonos
toolset
tshe
ubuntu
uiatextrange
UIs
und
@@ -96,5 +102,7 @@ versioned
vsdevcmd
We'd
wildcards
XBox
YBox
yeru
zhe

View File

@@ -32,10 +32,10 @@ DERR
dlldata
DNE
DONTADDTORECENT
DWMWA
DWORDLONG
DWMSBT
DWMWA
DWMWA
DWORDLONG
endfor
ENDSESSION
enumset
@@ -92,6 +92,7 @@ istream
IStringable
ITab
ITaskbar
itow
IUri
IVirtual
KEYSELECT
@@ -103,13 +104,14 @@ lround
Lsa
lsass
LSHIFT
LTGRAY
MAINWINDOW
memchr
memicmp
MENUCOMMAND
MENUDATA
MENUITEMINFOW
MENUINFO
MENUITEMINFOW
mmeapi
MOUSELEAVE
mov
@@ -146,6 +148,7 @@ OUTLINETEXTMETRICW
overridable
PACL
PAGESCROLL
PATINVERT
PEXPLICIT
PICKFOLDERS
pmr
@@ -155,8 +158,8 @@ rcx
REGCLS
RETURNCMD
rfind
roundf
ROOTOWNER
roundf
RSHIFT
SACL
schandle
@@ -208,6 +211,7 @@ UPDATEINIFILE
userenv
USEROBJECTFLAGS
Viewbox
virtualalloc
wcsstr
wcstoui
winmain

View File

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

View File

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

View File

@@ -5,26 +5,19 @@ AAAAAABBBBBBCCC
AAAAABBBBBBCCC
abcd
abcd
abcde
abcdef
ABCDEFG
ABCDEFGH
ABCDEFGHIJ
abcdefghijk
ABCDEFGHIJKLMNO
abcdefghijklmnop
ABCDEFGHIJKLMNOPQRST
abcdefghijklmnopqrstuvwxyz
ABCG
ABE
abf
BBBBB
BBBBBBBB
BBBBBBBBBBBBBBDDDD
BBBBBCCC
BBBBCCCCC
BBGGRR
CCE
EFG
EFGh
QQQQQQQQQQABCDEFGHIJ

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,3 @@
http
www
WCAG
winui
appshellintegration

View File

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

View File

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

View File

@@ -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.*

View File

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

View File

@@ -174,8 +174,7 @@ public:
const TextBuffer& GetTextBuffer() const noexcept override;
const FontInfo& GetFontInfo() const noexcept override;
void LockConsole() noexcept override;
void UnlockConsole() noexcept override;
[[nodiscard]] std::unique_lock<til::ticket_lock> LockConsole() noexcept override;
#pragma endregion
#pragma region IRenderData

View File

@@ -203,23 +203,17 @@ catch (...)
// - Lock the terminal for reading the contents of the buffer. Ensures that the
// contents of the terminal won't be changed in the middle of a paint
// operation.
// Callers should make sure to also call Terminal::UnlockConsole once
// they're done with any querying they need to do.
void Terminal::LockConsole() noexcept
std::unique_lock<til::ticket_lock> Terminal::LockConsole() noexcept
{
_readWriteLock.lock();
#ifndef NDEBUG
#ifdef NDEBUG
return std::unique_lock{ _readWriteLock };
#else
auto lock = std::unique_lock{ _readWriteLock };
_lastLocker = GetCurrentThreadId();
return lock;
#endif
}
// Method Description:
// - Unlocks the terminal after a call to Terminal::LockConsole.
void Terminal::UnlockConsole() noexcept
{
_readWriteLock.unlock();
}
const bool Terminal::IsUiaDataInitialized() const noexcept
{
// GH#11135: Windows Terminal needs to create and return an automation peer

View File

@@ -1912,8 +1912,7 @@ void ConptyRoundtripTests::ClearHostTrickeryTest()
// We're _not_ checking the conpty output during this test, only the side effects.
_checkConptyOutput = false;
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
Log::Comment(L"Setting up the host buffer...");
hostSm.ProcessString(L"AAAAA");
@@ -2404,8 +2403,7 @@ void ConptyRoundtripTests::BreakLinesOnCursorMovement()
_checkConptyOutput = false;
// Lock must be taken to manipulate alt/main buffer state.
gci.LockConsole();
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
// Use DECALN to fill the buffer with 'E's.
hostSm.ProcessString(L"\x1b#8");
@@ -3895,8 +3893,7 @@ void ConptyRoundtripTests::SimpleAltBufferTest()
Log::Comment(L"========== Switch to the alt buffer ==========");
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
sm.ProcessString(L"\x1b[?1049h");
// Don't leave ourselves in the alt buffer - that'll pollute other tests.
auto leaveAltBuffer = wil::scope_exit([&] { sm.ProcessString(L"\x1b[?1049l"); });
@@ -4056,8 +4053,7 @@ void ConptyRoundtripTests::AltBufferToAltBufferTest()
Log::Comment(L"========== Switch to the alt buffer ==========");
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
sm.ProcessString(L"\x1b[?1049h");
// Don't leave ourselves in the alt buffer - that'll pollute other tests.
auto leaveAltBuffer = wil::scope_exit([&] { sm.ProcessString(L"\x1b[?1049l"); });
@@ -4120,8 +4116,7 @@ void ConptyRoundtripTests::AltBufferResizeCrash()
auto& si = gci.GetActiveOutputBuffer();
auto& sm = si.GetStateMachine();
gci.LockConsole(); // Lock must be taken to manipulate alt/main buffer state.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
_flushFirstFrame();

View File

@@ -19,9 +19,8 @@ static void CALLBACK CursorTimerRoutineWrapper(_Inout_ PTP_CALLBACK_INSTANCE /*I
// But I'm not too concerned that this will lead to issues at the time of writing,
// as CursorBlinker is allocated as a static variable through the Globals class.
// It'd be nice to fix this, but realistically it'll likely not lead to issues.
gci.LockConsole();
const auto guard = gci.LockConsole();
gci.GetCursorBlinker().TimerRoutine(gci.GetActiveOutputBuffer());
gci.UnlockConsole();
}
CursorBlinker::CursorBlinker() :

View File

@@ -108,8 +108,7 @@ void PtySignalInputThread::CreatePseudoWindow()
ShowHideData msg = { 0 };
_GetData(&msg, sizeof(msg));
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// If the client app hasn't yet connected, stash our initial
// visibility for when we do. We default to not being visible - if a
@@ -132,8 +131,7 @@ void PtySignalInputThread::CreatePseudoWindow()
}
case PtySignal::ClearBuffer:
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// If the client app hasn't yet connected, stash the new size in the launchArgs.
// We'll later use the value in launchArgs to set up the console buffer
@@ -150,8 +148,7 @@ void PtySignalInputThread::CreatePseudoWindow()
ResizeWindowData resizeMsg = { 0 };
_GetData(&resizeMsg, sizeof(resizeMsg));
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// If the client app hasn't yet connected, stash the new size in the launchArgs.
// We'll later use the value in launchArgs to set up the console buffer
@@ -173,8 +170,7 @@ void PtySignalInputThread::CreatePseudoWindow()
SetParentData reparentMessage = { 0 };
_GetData(&reparentMessage, sizeof(reparentMessage));
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// If the client app hasn't yet connected, stash the new owner.
// We'll later (PtySignalInputThread::ConnectConsole) use the value

View File

@@ -66,8 +66,7 @@ VtInputThread::VtInputThread(_In_ wil::unique_hfile hPipe,
// gci's unlock, when you press C-c, it won't be dispatched until the
// next console API call. For something like `powershell sleep 60`,
// that won't happen for 60s
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{

View File

@@ -81,8 +81,7 @@ void WriteToScreen(SCREEN_INFORMATION& screenInfo, const Viewport& region)
return S_OK;
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& screenInfo = OutContext.GetActiveBuffer();
const auto bufferSize = screenInfo.GetBufferSize();
@@ -121,8 +120,7 @@ void WriteToScreen(SCREEN_INFORMATION& screenInfo, const Viewport& region)
return S_OK;
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& screenInfo = OutContext.GetActiveBuffer();
const auto bufferSize = screenInfo.GetBufferSize();
@@ -206,8 +204,7 @@ void WriteToScreen(SCREEN_INFORMATION& screenInfo, const Viewport& region)
return S_OK;
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& screenBuffer = OutContext.GetActiveBuffer();
const auto bufferSize = screenBuffer.GetBufferSize();
@@ -266,8 +263,7 @@ void WriteToScreen(SCREEN_INFORMATION& screenInfo, const Viewport& region)
return S_OK;
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// TODO: does this even need to be here or will it exit quickly?
auto& screenInfo = OutContext.GetActiveBuffer();

View File

@@ -1137,8 +1137,7 @@ using Microsoft::Console::VirtualTerminal::StateMachine;
return S_OK;
}
LockConsole();
auto unlock{ wil::scope_exit([&] { UnlockConsole(); }) };
const auto lock = LockConsole();
auto& screenInfo{ context.GetActiveBuffer() };
const auto& consoleInfo{ ServiceLocator::LocateGlobals().getConsoleInformation() };
@@ -1318,8 +1317,7 @@ using Microsoft::Console::VirtualTerminal::StateMachine;
{
try
{
LockConsole();
auto unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
std::unique_ptr<WriteData> writeDataWaiter;
RETURN_IF_FAILED(WriteConsoleWImplHelper(context.GetActiveBuffer(), buffer, read, requiresVtQuirk, writeDataWaiter));

View File

@@ -88,8 +88,7 @@ std::unordered_map<std::wstring,
const std::wstring_view target,
const std::wstring_view exeName) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
RETURN_HR_IF(E_INVALIDARG, source.size() == 0);
@@ -211,8 +210,7 @@ std::unordered_map<std::wstring,
til::at(target, 0) = ANSI_NULL;
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Convert our input parameters to Unicode.
const auto sourceW = ConvertToW(codepage, source);
@@ -272,8 +270,7 @@ std::unordered_map<std::wstring,
size_t& written,
const std::wstring_view exeName) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -379,8 +376,7 @@ static std::wstring aliasesSeparator(L"=");
// Ensure output variables are initialized
bufferRequired = 0;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Convert our input parameters to Unicode
try
@@ -403,8 +399,7 @@ static std::wstring aliasesSeparator(L"=");
[[nodiscard]] HRESULT ApiRoutines::GetConsoleAliasesLengthWImpl(const std::wstring_view exeName,
size_t& bufferRequired) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -543,8 +538,7 @@ void Alias::s_ClearCmdExeAliases()
til::at(alias, 0) = '\0';
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Convert our input parameters to Unicode.
const auto exeNameW = ConvertToW(codepage, exeName);
@@ -594,8 +588,7 @@ void Alias::s_ClearCmdExeAliases()
gsl::span<wchar_t> alias,
size_t& written) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -653,9 +646,8 @@ void Alias::s_ClearCmdExeAliases()
// - Check HRESULT with SUCCEEDED. Can return memory, safe math, safe string, or locale conversion errors.
[[nodiscard]] HRESULT ApiRoutines::GetConsoleAliasExesLengthAImpl(size_t& bufferRequired) noexcept
{
LockConsole();
const auto lock = LockConsole();
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
return GetConsoleAliasExesLengthImplHelper(false, gci.CP, bufferRequired);
}
@@ -668,8 +660,7 @@ void Alias::s_ClearCmdExeAliases()
// - Check HRESULT with SUCCEEDED. Can return memory, safe math, safe string, or locale conversion errors.
[[nodiscard]] HRESULT ApiRoutines::GetConsoleAliasExesLengthWImpl(size_t& bufferRequired) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
return GetConsoleAliasExesLengthImplHelper(true, 0, bufferRequired);
}
@@ -761,8 +752,7 @@ void Alias::s_ClearCmdExeAliases()
til::at(aliasExes, 0) = '\0';
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Figure our how big our temporary Unicode buffer must be to retrieve output
size_t bufferNeeded;
@@ -807,8 +797,7 @@ void Alias::s_ClearCmdExeAliases()
[[nodiscard]] HRESULT ApiRoutines::GetConsoleAliasExesWImpl(gsl::span<wchar_t> aliasExes,
size_t& written) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{

View File

@@ -11,8 +11,6 @@
#include "../interactivity/inc/ServiceLocator.hpp"
#include "../types/inc/convert.hpp"
#include <til/ticket_lock.h>
using Microsoft::Console::Interactivity::ServiceLocator;
using Microsoft::Console::VirtualTerminal::VtIo;
@@ -47,50 +45,24 @@ CONSOLE_INFORMATION::CONSOLE_INFORMATION() :
ZeroMemory((void*)&OutputCPInfo, sizeof(OutputCPInfo));
}
// Access to thread-local variables is thread-safe, because each thread
// gets its own copy of this variable with a default value of 0.
//
// Whenever we want to acquire the lock we increment recursionCount and on
// each release we decrement it again. We can then make the lock safe for
// reentrancy by only acquiring/releasing the lock if the recursionCount is 0.
// In a sense, recursionCount is counting the actual function
// call recursion depth of the caller. This works as long as
// the caller makes sure to properly call Unlock() once for each Lock().
static thread_local ULONG recursionCount = 0;
static til::ticket_lock lock;
bool CONSOLE_INFORMATION::IsConsoleLocked()
std::unique_lock<til::recursive_ticket_lock> CONSOLE_INFORMATION::LockConsole()
{
return recursionCount != 0;
return std::unique_lock{ _lock };
}
#pragma prefast(suppress : 26135, "Adding lock annotation spills into entire project. Future work.")
void CONSOLE_INFORMATION::LockConsole()
til::recursive_ticket_lock_suspension CONSOLE_INFORMATION::SuspendConsoleLock()
{
// See description of recursionCount a few lines above.
const auto rc = ++recursionCount;
FAIL_FAST_IF(rc == 0);
if (rc == 1)
{
lock.lock();
}
return _lock.suspend();
}
#pragma prefast(suppress : 26135, "Adding lock annotation spills into entire project. Future work.")
void CONSOLE_INFORMATION::UnlockConsole()
bool CONSOLE_INFORMATION::IsConsoleLocked() const
{
// See description of recursionCount a few lines above.
const auto rc = --recursionCount;
FAIL_FAST_IF(rc == ULONG_MAX);
if (rc == 0)
{
lock.unlock();
}
return _lock.is_locked();
}
ULONG CONSOLE_INFORMATION::GetCSRecursionCount()
ULONG CONSOLE_INFORMATION::GetCSRecursionCount() const
{
return recursionCount;
return _lock.recursion_depth();
}
// Routine Description:
@@ -401,9 +373,8 @@ void CONSOLE_INFORMATION::ShutdownMidiAudio()
{
// We lock the console here to make sure the shutdown promise is
// set before the audio is unlocked in the thread that is playing.
LockConsole();
const auto guard = LockConsole();
_midiAudio->Shutdown();
UnlockConsole();
}
}

View File

@@ -89,8 +89,7 @@ void WriteConvRegionToScreen(const SCREEN_INFORMATION& ScreenInfo,
[[nodiscard]] HRESULT ImeStartComposition()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole();
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
// MSFT:29219348 Some IME implementations do not produce composition strings, and
// their users have come to rely on the cursor that conhost traditionally left on
@@ -105,8 +104,7 @@ void WriteConvRegionToScreen(const SCREEN_INFORMATION& ScreenInfo,
[[nodiscard]] HRESULT ImeEndComposition()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole();
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
const auto pIme = &gci.ConsoleIme;
pIme->RestoreCursorVisibility();
@@ -122,8 +120,7 @@ void WriteConvRegionToScreen(const SCREEN_INFORMATION& ScreenInfo,
try
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole();
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
const auto pIme = &gci.ConsoleIme;
pIme->WriteCompMessage(text, attributes, colorArray);
@@ -137,8 +134,7 @@ void WriteConvRegionToScreen(const SCREEN_INFORMATION& ScreenInfo,
try
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole();
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
const auto pIme = &gci.ConsoleIme;
pIme->ClearAllAreas();
@@ -152,8 +148,7 @@ void WriteConvRegionToScreen(const SCREEN_INFORMATION& ScreenInfo,
try
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole();
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
const auto pIme = &gci.ConsoleIme;
pIme->WriteResultMessage(text);

View File

@@ -166,8 +166,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
return STATUS_SUCCESS;
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
std::deque<std::unique_ptr<IInputEvent>> partialEvents;
if (!IsUnicode)
@@ -458,8 +457,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
{
written = 0;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -502,8 +500,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
{
written = 0;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -816,8 +813,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
const Microsoft::Console::Types::Viewport& sourceRectangle,
Microsoft::Console::Types::Viewport& readRectangle) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -838,8 +834,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
const Microsoft::Console::Types::Viewport& sourceRectangle,
Microsoft::Console::Types::Viewport& readRectangle) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -962,8 +957,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
const Viewport& requestRectangle,
Viewport& writtenRectangle) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -983,8 +977,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
const Viewport& requestRectangle,
Viewport& writtenRectangle) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -1012,8 +1005,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
{
written = 0;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -1033,8 +1025,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
{
written = 0;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -1062,8 +1053,7 @@ void EventsToUnicode(_Inout_ std::deque<std::unique_ptr<IInputEvent>>& inEvents,
{
written = 0;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{

View File

@@ -69,7 +69,7 @@ struct NullDeviceComm : public IDeviceComm
auto& gci = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().getConsoleInformation();
// Process handle list manipulation must be done under lock
gci.LockConsole();
const auto guard = gci.LockConsole();
ConsoleProcessHandle* pProcessHandle{ nullptr };
RETURN_IF_FAILED(gci.ProcessHandleList.AllocProcessData(GetCurrentProcessId(),
GetCurrentThreadId(),
@@ -95,8 +95,6 @@ struct NullDeviceComm : public IDeviceComm
CommandHistory::s_Allocate(fakeTitle, (HANDLE)pProcessHandle);
gci.UnlockConsole();
return S_OK;
}
@@ -134,8 +132,7 @@ extern "C" __declspec(dllexport) int LLVMFuzzerTestOneInput(const uint8_t* data,
const auto u16String{ til::u8u16(std::string_view{ reinterpret_cast<const char*>(data), size }) };
til::CoordType scrollY{};
auto sizeInBytes{ u16String.size() * 2 };
gci.LockConsole();
auto u = wil::scope_exit([&]() { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
(void)WriteCharsLegacy(gci.GetActiveOutputBuffer(),
u16String.data(),
u16String.data(),

View File

@@ -43,8 +43,7 @@ void ApiRoutines::GetConsoleInputModeImpl(InputBuffer& context, ULONG& mode) noe
{
Telemetry::Instance().LogApiCall(Telemetry::ApiCall::GetConsoleMode);
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
mode = context.InputMode;
@@ -68,8 +67,7 @@ void ApiRoutines::GetConsoleOutputModeImpl(SCREEN_INFORMATION& context, ULONG& m
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
mode = context.GetActiveBuffer().OutputMode;
}
@@ -87,8 +85,7 @@ void ApiRoutines::GetConsoleOutputModeImpl(SCREEN_INFORMATION& context, ULONG& m
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
const auto readyEventCount = context.GetNumberOfReadyEvents();
RETURN_IF_FAILED(SizeTToULong(readyEventCount, &events));
@@ -108,8 +105,7 @@ void ApiRoutines::GetConsoleScreenBufferInfoExImpl(const SCREEN_INFORMATION& con
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
data.bFullscreenSupported = FALSE; // traditional full screen with the driver support is no longer supported.
// see MSFT: 19918103
@@ -162,8 +158,7 @@ void ApiRoutines::GetConsoleCursorInfoImpl(const SCREEN_INFORMATION& context,
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
size = context.GetActiveBuffer().GetTextBuffer().GetCursor().GetSize();
isVisible = context.GetTextBuffer().GetCursor().IsVisible();
@@ -179,8 +174,7 @@ void ApiRoutines::GetConsoleSelectionInfoImpl(CONSOLE_SELECTION_INFO& consoleSel
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
const auto& selection = Selection::Instance();
if (selection.IsInSelectingState())
@@ -208,8 +202,7 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
buttons = ServiceLocator::LocateSystemConfigurationProvider()->GetNumberOfMouseButtons();
}
@@ -230,8 +223,7 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
if (index == 0)
{
@@ -263,8 +255,7 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
const auto& activeScreenInfo = context.GetActiveBuffer();
@@ -306,8 +297,7 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
try
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& activeScreenInfo = context.GetActiveBuffer();
@@ -340,8 +330,7 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
try
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
const auto oldQuickEditMode{ WI_IsFlagSet(gci.Flags, CONSOLE_QUICK_EDIT_MODE) };
@@ -416,8 +405,7 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
try
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Flags we don't understand are invalid.
RETURN_HR_IF(E_INVALIDARG, WI_IsAnyFlagSet(mode, ~OUTPUT_MODES));
@@ -466,8 +454,7 @@ void ApiRoutines::SetConsoleActiveScreenBufferImpl(SCREEN_INFORMATION& newContex
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
SetActiveScreenBuffer(newContext.GetActiveBuffer());
}
@@ -482,8 +469,7 @@ void ApiRoutines::FlushConsoleInputBuffer(InputBuffer& context) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
context.Flush();
}
@@ -500,8 +486,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
const auto& screenInfo = context.GetActiveBuffer();
@@ -522,8 +507,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& screenInfo = context.GetActiveBuffer();
@@ -592,8 +576,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
data.dwSize.Y == SHRT_MAX));
// clang-format on
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& g = ServiceLocator::LocateGlobals();
auto& gci = g.getConsoleInformation();
@@ -716,8 +699,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& buffer = context.GetActiveBuffer();
@@ -801,8 +783,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// If more than 100% or less than 0% cursor height, reject it.
RETURN_HR_IF(E_INVALIDARG, (size > 100 || size == 0));
@@ -829,8 +810,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& g = ServiceLocator::LocateGlobals();
auto Window = windowRect;
@@ -938,8 +918,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& buffer = context.GetActiveBuffer();
@@ -996,8 +975,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
RETURN_HR_IF(E_INVALIDARG, WI_IsAnyFlagSet(attribute, ~VALID_TEXT_ATTRIBUTES));
@@ -1040,8 +1018,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
return DoSrvSetConsoleOutputCodePage(codepage);
}
CATCH_RETURN();
@@ -1058,8 +1035,7 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
try
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Return if it's not known as a valid codepage ID.
RETURN_HR_IF(E_INVALIDARG, !(IsValidCodePage(codepage)));
@@ -1087,8 +1063,7 @@ void ApiRoutines::GetConsoleInputCodePageImpl(ULONG& codepage) noexcept
try
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
codepage = gci.CP;
}
@@ -1103,8 +1078,7 @@ void ApiRoutines::GetConsoleOutputCodePageImpl(ULONG& codepage) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
codepage = gci.OutputCP;
}
@@ -1122,8 +1096,7 @@ void ApiRoutines::GetConsoleWindowImpl(HWND& hwnd) noexcept
// Set return to null before we do anything in case of failures/errors.
hwnd = nullptr;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
const IConsoleWindow* pWindow = ServiceLocator::LocateConsoleWindow();
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
if (pWindow != nullptr)
@@ -1155,8 +1128,7 @@ void ApiRoutines::GetConsoleHistoryInfoImpl(CONSOLE_HISTORY_INFO& consoleHistory
try
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
consoleHistoryInfo.HistoryBufferSize = gci.GetHistoryBufferSize();
consoleHistoryInfo.NumberOfHistoryBuffers = gci.GetNumberOfHistoryBuffers();
@@ -1180,8 +1152,7 @@ HRESULT ApiRoutines::SetConsoleHistoryInfoImpl(const CONSOLE_HISTORY_INFO& conso
RETURN_HR_IF(E_INVALIDARG, consoleHistoryInfo.NumberOfHistoryBuffers > SHORT_MAX);
RETURN_HR_IF(E_INVALIDARG, WI_IsAnyFlagSet(consoleHistoryInfo.dwFlags, ~CHI_VALID_FLAGS));
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
CommandHistory::s_ResizeAll(consoleHistoryInfo.HistoryBufferSize);
gci.SetNumberOfHistoryBuffers(consoleHistoryInfo.NumberOfHistoryBuffers);
@@ -1202,8 +1173,7 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Initialize flags portion of structure
flags = 0;
@@ -1241,9 +1211,8 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
// SetIsFullscreen() below ultimately calls SetwindowLong, which ultimately calls SendMessage(). If we retain
// the console lock, we'll deadlock since ConsoleWindowProc takes the lock before processing messages. Instead,
// we'll release early.
LockConsole();
{
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
auto& screenInfo = context.GetActiveBuffer();
@@ -1431,8 +1400,7 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
return GetConsoleTitleAImplHelper(title, written, needed, false);
}
@@ -1454,8 +1422,7 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
return GetConsoleTitleWImplHelper(title, written, needed, false);
}
@@ -1477,8 +1444,7 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
return GetConsoleTitleAImplHelper(title, written, needed, true);
}
@@ -1500,8 +1466,7 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
return GetConsoleTitleWImplHelper(title, written, needed, true);
}
@@ -1535,8 +1500,7 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept
// - S_OK, E_INVALIDARG, or failure code from thrown exception
[[nodiscard]] HRESULT ApiRoutines::SetConsoleTitleWImpl(const std::wstring_view title) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
ServiceLocator::LocateGlobals().getConsoleInformation().SetTitle(title);
return S_OK;

View File

@@ -10,21 +10,22 @@
using Microsoft::Console::Interactivity::ServiceLocator;
void LockConsole()
LockConsoleGuard::LockConsoleGuard(std::unique_lock<til::recursive_ticket_lock>&& guard) noexcept :
_guard{ std::move(guard) }
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole();
}
void UnlockConsole()
LockConsoleGuard::~LockConsoleGuard()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
if (gci.GetCSRecursionCount() == 1)
{
ProcessCtrlEvents();
}
else
{
gci.UnlockConsole();
}
}
LockConsoleGuard LockConsole()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
return LockConsoleGuard{ gci.LockConsole() };
}

View File

@@ -17,5 +17,15 @@ Revision History:
#pragma once
void LockConsole();
void UnlockConsole();
#include <til/ticket_lock.h>
struct LockConsoleGuard
{
explicit LockConsoleGuard(std::unique_lock<til::recursive_ticket_lock>&& guard) noexcept;
~LockConsoleGuard();
private:
std::unique_lock<til::recursive_ticket_lock> _guard;
};
LockConsoleGuard LockConsole();

View File

@@ -588,8 +588,7 @@ HRESULT ApiRoutines::ExpungeConsoleCommandHistoryAImpl(const std::string_view ex
// - Check HRESULT with SUCCEEDED. Can return memory, safe math, safe string, or locale conversion errors.
HRESULT ApiRoutines::ExpungeConsoleCommandHistoryWImpl(const std::wstring_view exeName) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -636,8 +635,7 @@ HRESULT ApiRoutines::SetConsoleNumberOfCommandsAImpl(const std::string_view exeN
HRESULT ApiRoutines::SetConsoleNumberOfCommandsWImpl(const std::wstring_view exeName,
const size_t numberOfCommands) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -668,8 +666,7 @@ HRESULT GetConsoleCommandHistoryLengthImplHelper(const std::wstring_view exeName
// Ensure output variables are initialized
historyLength = 0;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
const auto pCommandHistory = CommandHistory::s_FindByExe(exeName);
if (nullptr != pCommandHistory)
@@ -721,8 +718,7 @@ HRESULT ApiRoutines::GetConsoleCommandHistoryLengthAImpl(const std::string_view
// Ensure output variables are initialized
length = 0;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -742,8 +738,7 @@ HRESULT ApiRoutines::GetConsoleCommandHistoryLengthAImpl(const std::string_view
HRESULT ApiRoutines::GetConsoleCommandHistoryLengthWImpl(const std::wstring_view exeName,
size_t& length) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{
@@ -853,8 +848,7 @@ HRESULT ApiRoutines::GetConsoleCommandHistoryAImpl(const std::string_view exeNam
til::at(commandHistory, 0) = ANSI_NULL;
}
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Convert our input parameters to Unicode.
const auto exeNameW = ConvertToW(codepage, exeName);
@@ -904,8 +898,7 @@ HRESULT ApiRoutines::GetConsoleCommandHistoryWImpl(const std::wstring_view exeNa
gsl::span<wchar_t> commandHistory,
size_t& written) noexcept
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
try
{

View File

@@ -521,6 +521,5 @@ void CloseConsoleProcessState()
// not running under lock (eg PtySignalInputThread::_GetData), then the
// ctrl event will never actually get dispatched.
// So, lock and unlock here, to make sure the ctrl event gets handled.
LockConsole();
UnlockConsole();
std::ignore = LockConsole();
}

View File

@@ -375,19 +375,22 @@ void ConhostInternalGetSet::PlayMidiNote(const int noteNumber, const int velocit
{
// We create the audio instance on demand, and lock it for the duration
// of the note output so it can't be destroyed while in use.
auto& midiAudio = ServiceLocator::LocateGlobals().getConsoleInformation().GetMidiAudio();
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& midiAudio = gci.GetMidiAudio();
midiAudio.Lock();
// We then unlock the console, so the UI doesn't hang while we're busy.
UnlockConsole();
{
// We then unlock the console, so the UI doesn't hang while we're busy.
const auto guard = gci.SuspendConsoleLock();
// This call will block for the duration, unless shutdown early.
midiAudio.PlayNote(noteNumber, velocity, duration);
// This call will block for the duration, unless shutdown early.
midiAudio.PlayNote(noteNumber, velocity, duration);
// Once complete, we reacquire the console lock and unlock the audio.
}
// Once complete, we reacquire the console lock and unlock the audio.
// If the console has shutdown in the meantime, the Unlock call
// will throw an exception, forcing the thread to exit ASAP.
LockConsole();
midiAudio.Unlock();
}

View File

@@ -86,16 +86,11 @@ std::vector<Viewport> RenderData::GetSelectionRects() noexcept
// operation.
// Callers should make sure to also call RenderData::UnlockConsole once
// they're done with any querying they need to do.
void RenderData::LockConsole() noexcept
std::unique_lock<til::ticket_lock> RenderData::LockConsole() noexcept
{
::LockConsole();
}
// Method Description:
// - Unlocks the console after a call to RenderData::LockConsole.
void RenderData::UnlockConsole() noexcept
{
::UnlockConsole();
__debugbreak();
return {};
}
#pragma endregion

View File

@@ -31,8 +31,7 @@ public:
std::vector<Microsoft::Console::Types::Viewport> GetSelectionRects() noexcept override;
void LockConsole() noexcept override;
void UnlockConsole() noexcept override;
[[nodiscard]] std::unique_lock<til::ticket_lock> LockConsole() noexcept override;
#pragma endregion
#pragma region IRenderData

View File

@@ -30,6 +30,8 @@ Revision History:
#include "../host/RenderData.hpp"
#include "../audio/midi/MidiAudio.hpp"
#include <til/ticket_lock.h>
// clang-format off
// Flags flags
#define CONSOLE_IS_ICONIC 0x00000001
@@ -103,10 +105,10 @@ public:
ConsoleImeInfo ConsoleIme;
static void LockConsole();
static void UnlockConsole();
static bool IsConsoleLocked();
static ULONG GetCSRecursionCount();
[[nodiscard]] std::unique_lock<til::recursive_ticket_lock> LockConsole();
[[nodiscard]] til::recursive_ticket_lock_suspension SuspendConsoleLock();
bool IsConsoleLocked() const;
ULONG GetCSRecursionCount() const;
Microsoft::Console::VirtualTerminal::VtIo* GetVtIo();
@@ -147,6 +149,8 @@ public:
RenderData renderData;
private:
til::recursive_ticket_lock _lock;
std::wstring _Title;
std::wstring _Prefix; // Eg Select, Mark - things that we manually prepend to the title.
std::wstring _TitleAndPrefix;

View File

@@ -249,7 +249,7 @@ static bool s_IsOnDesktop()
[[nodiscard]] NTSTATUS RemoveConsole(_In_ ConsoleProcessHandle* ProcessData)
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
const auto guard = LockConsole();
auto Status = STATUS_SUCCESS;
CommandHistory::s_Free((HANDLE)ProcessData);
@@ -266,8 +266,6 @@ static bool s_IsOnDesktop()
}
}
UnlockConsole();
return Status;
}
@@ -708,8 +706,7 @@ PWSTR TranslateConsoleTitle(_In_ PCWSTR pwszConsoleTitle, const BOOL fUnexpand,
try
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// This fails a lot and it's totally expected. It only works for a few East Asian code pages.
// As such, just return it. Do NOT use a wil macro here. It is very noisy.

View File

@@ -694,8 +694,7 @@ til::CoordType RetrieveNumberOfSpaces(_In_ til::CoordType sOriginalCursorPositio
{
try
{
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
waiter.reset();

View File

@@ -340,8 +340,7 @@ class ApiRoutinesTests
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
gci.LockConsole();
auto Unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
// Ensure global state is updated for our codepage.
gci.OutputCP = dwCodePage;
@@ -430,8 +429,7 @@ class ApiRoutinesTests
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer();
gci.LockConsole();
auto Unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
const std::wstring testText(L"Test text");
@@ -616,8 +614,7 @@ class ApiRoutinesTests
// Make sure we clear the margins on exit so they can't break other tests.
auto clearMargins = wil::scope_exit([&] { stateMachine.ProcessString(L"\x1b[r"); });
gci.LockConsole();
auto Unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole();
CHAR_INFO fill;
fill.Char.UnicodeChar = L'A';

View File

@@ -251,8 +251,7 @@ class ScreenBufferTests
void ScreenBufferTests::SingleAlternateBufferCreationTest()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
Log::Comment(L"Testing creating one alternate buffer, then returning to the main buffer.");
const auto psiOriginal = &gci.GetActiveOutputBuffer();
@@ -283,8 +282,7 @@ void ScreenBufferTests::SingleAlternateBufferCreationTest()
void ScreenBufferTests::MultipleAlternateBufferCreationTest()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
Log::Comment(
L"Testing creating one alternate buffer, then creating another "
@@ -330,8 +328,7 @@ void ScreenBufferTests::MultipleAlternateBufferCreationTest()
void ScreenBufferTests::MultipleAlternateBuffersFromMainCreationTest()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
Log::Comment(
L"Testing creating one alternate buffer, then creating another"
@@ -375,8 +372,7 @@ void ScreenBufferTests::MultipleAlternateBuffersFromMainCreationTest()
void ScreenBufferTests::AlternateBufferCursorInheritanceTest()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto& mainBuffer = gci.GetActiveOutputBuffer();
auto& mainCursor = mainBuffer.GetTextBuffer().GetCursor();
@@ -872,8 +868,7 @@ void ScreenBufferTests::TestGetReverseTab()
void ScreenBufferTests::TestAltBufferTabStops()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to swap buffers.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to swap buffers.
auto& mainBuffer = gci.GetActiveOutputBuffer();
// Make sure we're in VT mode
@@ -2029,8 +2024,7 @@ void ScreenBufferTests::ResizeCursorUnchanged()
void ScreenBufferTests::ResizeAltBuffer()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto& si = gci.GetActiveOutputBuffer().GetActiveBuffer();
auto& stateMachine = si.GetStateMachine();
@@ -2084,8 +2078,7 @@ void ScreenBufferTests::ResizeAltBufferGetScreenBufferInfo()
auto& g = ServiceLocator::LocateGlobals();
auto& gci = g.getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto& mainBuffer = gci.GetActiveOutputBuffer().GetActiveBuffer();
auto& stateMachine = mainBuffer.GetStateMachine();
@@ -2352,8 +2345,7 @@ void ScreenBufferTests::GetWordBoundaryTrimZerosOff()
void ScreenBufferTests::TestAltBufferCursorState()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
Log::Comment(L"Creating one alternate buffer");
auto& original = gci.GetActiveOutputBuffer();
@@ -2392,8 +2384,7 @@ void ScreenBufferTests::TestAltBufferCursorState()
void ScreenBufferTests::TestAltBufferVtDispatching()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
Log::Comment(L"Creating one alternate buffer");
auto& mainBuffer = gci.GetActiveOutputBuffer();
// Make sure we're in VT mode
@@ -2484,8 +2475,7 @@ void ScreenBufferTests::TestAltBufferVtDispatching()
void ScreenBufferTests::TestAltBufferRIS()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto& si = gci.GetActiveOutputBuffer();
auto& stateMachine = si.GetStateMachine();
@@ -2963,8 +2953,7 @@ void ScreenBufferTests::SetGlobalColorTable()
// tested.
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to swap buffers.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to swap buffers.
auto& mainBuffer = gci.GetActiveOutputBuffer();
VERIFY_IS_FALSE(mainBuffer._IsAltBuffer());
@@ -3070,8 +3059,7 @@ void ScreenBufferTests::SetColorTableThreeDigits()
// Changing the value of the color table above index 99 should work
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to swap buffers.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to swap buffers.
auto& mainBuffer = gci.GetActiveOutputBuffer();
VERIFY_IS_FALSE(mainBuffer._IsAltBuffer());
@@ -3154,8 +3142,7 @@ void ScreenBufferTests::SetDefaultForegroundColor()
// Setting the default foreground color should work
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to swap buffers.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to swap buffers.
auto& mainBuffer = gci.GetActiveOutputBuffer();
VERIFY_IS_FALSE(mainBuffer._IsAltBuffer());
@@ -3199,8 +3186,7 @@ void ScreenBufferTests::SetDefaultBackgroundColor()
// Setting the default Background color should work
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to swap buffers.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to swap buffers.
auto& mainBuffer = gci.GetActiveOutputBuffer();
VERIFY_IS_FALSE(mainBuffer._IsAltBuffer());
@@ -5143,8 +5129,7 @@ void ScreenBufferTests::RestoreDownAltBufferWithTerminalScrolling()
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.SetTerminalScrolling(true);
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto& siMain = gci.GetActiveOutputBuffer();
auto coordFontSize = siMain.GetScreenFontSize();
@@ -5210,8 +5195,7 @@ void ScreenBufferTests::SnapCursorWithTerminalScrolling()
auto& g = ServiceLocator::LocateGlobals();
auto& gci = g.getConsoleInformation();
gci.SetTerminalScrolling(true);
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto& si = gci.GetActiveOutputBuffer();
auto& cursor = si.GetTextBuffer().GetCursor();
@@ -5284,8 +5268,7 @@ void ScreenBufferTests::ClearAlternateBuffer()
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& g = ServiceLocator::LocateGlobals();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto& siMain = gci.GetActiveOutputBuffer();
auto WriteText = [&](TextBuffer& tbi) {
@@ -6766,8 +6749,7 @@ void ScreenBufferTests::TestWriteConsoleVTQuirkMode()
VERIFY_SUCCEEDED(TestData::TryGetValue(L"useQuirk", useQuirk), L"whether to enable the quirk");
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto& mainBuffer = gci.GetActiveOutputBuffer();
auto& cursor = mainBuffer.GetTextBuffer().GetCursor();
@@ -7134,8 +7116,7 @@ void ScreenBufferTests::TestDeferredMainBufferResize()
L"main buffer till we swap back to it, for performance.");
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
gci.LockConsole(); // Lock must be taken to manipulate buffer.
auto unlock = wil::scope_exit([&] { gci.UnlockConsole(); });
const auto lock = gci.LockConsole(); // Lock must be taken to manipulate buffer.
// HUGELY cribbed from ConptyRoundtripTests::MethodSetup. This fakes the
// console into thinking that it's in ConPTY mode. Yes, we need all this

View File

@@ -282,12 +282,9 @@ public:
return std::vector<Microsoft::Console::Types::Viewport>{};
}
void LockConsole() noexcept override
{
}
void UnlockConsole() noexcept override
std::unique_lock<til::ticket_lock> LockConsole() noexcept override
{
return {};
}
std::pair<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& /*attr*/) const noexcept override

View File

@@ -53,4 +53,89 @@ namespace til
std::atomic<uint32_t> _next_ticket{ 0 };
std::atomic<uint32_t> _now_serving{ 0 };
};
struct recursive_ticket_lock
{
struct recursive_ticket_lock_suspension
{
recursive_ticket_lock_suspension(recursive_ticket_lock& lock) :
_lock{ lock }
{
}
~recursive_ticket_lock_suspension()
{
if (_owner)
{
_lock._lock.lock(); // lock-lock-lock lol
_lock._owner.store(_owner, std::memory_order_relaxed);
_lock._recursion = _recursion;
}
}
private:
friend struct recursive_ticket_lock;
recursive_ticket_lock& _lock;
uint32_t _owner = 0;
uint32_t _recursion = 0;
};
void lock() noexcept
{
const auto id = GetCurrentThreadId();
if (_owner.load(std::memory_order_relaxed) != id)
{
_lock.lock();
_owner.store(id, std::memory_order_relaxed);
}
_recursion++;
}
void unlock() noexcept
{
if (--_recursion == 0)
{
_owner.store(0, std::memory_order_relaxed);
_lock.unlock();
}
}
[[nodiscard]] recursive_ticket_lock_suspension suspend() noexcept
{
const auto id = GetCurrentThreadId();
recursive_ticket_lock_suspension guard{ *this };
if (_owner.load(std::memory_order_relaxed) == id)
{
guard._owner = id;
guard._recursion = _recursion;
_owner.store(0, std::memory_order_relaxed);
_recursion = 0;
_lock.unlock();
}
return guard;
}
uint32_t is_locked() const noexcept
{
const auto id = GetCurrentThreadId();
return _owner.load(std::memory_order_relaxed) == id;
}
uint32_t recursion_depth() const noexcept
{
return is_locked() ? _recursion : 0;
}
private:
ticket_lock _lock;
std::atomic<uint32_t> _owner = 0;
uint32_t _recursion = 0;
};
using recursive_ticket_lock_suspension = recursive_ticket_lock::recursive_ticket_lock_suspension;
}

View File

@@ -62,7 +62,7 @@ void ServiceLocator::SetOneCoreTeardownFunction(void (*pfn)()) noexcept
#ifndef NDEBUG
// By locking the console, we ensure no background tasks are accessing the
// classes we're going to destruct down below (for instance: CursorBlinker).
s_globals.getConsoleInformation().LockConsole();
const auto guard = s_globals.getConsoleInformation().LockConsole();
#endif
// A History Lesson from MSFT: 13576341:

View File

@@ -18,9 +18,6 @@
// ConIoSrv.h, included above. For security-related considerations, see Trust.h
// in the ConIoSrv directory.
extern void LockConsole();
extern void UnlockConsole();
using namespace Microsoft::Console::Render;
using namespace Microsoft::Console::Interactivity::OneCore;
@@ -259,7 +256,7 @@ VOID ConIoSrvComm::ServiceInputPipe()
if (Ret != FALSE)
{
LockConsole();
const auto lock = LockConsole();
switch (Event.Type)
{
case CIS_EVENT_TYPE_INPUT:
@@ -280,7 +277,6 @@ VOID ConIoSrvComm::ServiceInputPipe()
default:
break;
}
UnlockConsole();
}
else
{

View File

@@ -53,8 +53,7 @@ INT_PTR CALLBACK FindDialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM l
std::wstring wstr(szBuf, StringLength);
lastFindString = wstr;
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
Search search(gci.renderData,
wstr,
@@ -92,7 +91,6 @@ void DoFind()
auto& g = ServiceLocator::LocateGlobals();
const auto pWindow = ServiceLocator::LocateConsoleWindow();
UnlockConsole();
if (pWindow != nullptr)
{
const auto hwnd = pWindow->GetWindowHandle();

View File

@@ -1022,35 +1022,36 @@ DWORD WINAPI ConsoleInputThreadProcWin32(LPVOID /*lpParameter*/)
{
InitEnvironmentVariables();
LockConsole();
HHOOK hhook = nullptr;
auto Status = STATUS_SUCCESS;
{
const auto lock = LockConsole();
if (!ServiceLocator::LocateGlobals().launchArgs.IsHeadless())
{
// If we're not headless, set up the main conhost window.
Status = InitWindowsSubsystem(&hhook);
}
else
{
// If we are headless (because we're a pseudo console), we
// will still need a window handle in the win32 environment
// in case anyone sends messages at that HWND (vim.exe is an example.)
//
// IMPORTANT! We have to CreateWindow on the same thread that will pump
// the messages, which is this thread. If you DON'T, then a DPI change
// in the owning hwnd will cause us to get a dpi change as well, which
// we'll never deque and handle, effectively HANGING THE OWNER HWND.
// ServiceLocator::LocatePseudoWindow();
//
// Instead of just calling LocatePseudoWindow, make sure to go through
// VtIo's CreatePseudoWindow, which will make sure that the window is
// successfully created with the owner configured when the window is
// first created. See GH#13066 for details.
ServiceLocator::LocateGlobals().getConsoleInformation().GetVtIo()->CreatePseudoWindow();
if (!ServiceLocator::LocateGlobals().launchArgs.IsHeadless())
{
// If we're not headless, set up the main conhost window.
Status = InitWindowsSubsystem(&hhook);
}
else
{
// If we are headless (because we're a pseudo console), we
// will still need a window handle in the win32 environment
// in case anyone sends messages at that HWND (vim.exe is an example.)
//
// IMPORTANT! We have to CreateWindow on the same thread that will pump
// the messages, which is this thread. If you DON'T, then a DPI change
// in the owning hwnd will cause us to get a dpi change as well, which
// we'll never deque and handle, effectively HANGING THE OWNER HWND.
// ServiceLocator::LocatePseudoWindow();
//
// Instead of just calling LocatePseudoWindow, make sure to go through
// VtIo's CreatePseudoWindow, which will make sure that the window is
// successfully created with the owner configured when the window is
// first created. See GH#13066 for details.
ServiceLocator::LocateGlobals().getConsoleInformation().GetVtIo()->CreatePseudoWindow();
}
}
UnlockConsole();
if (!NT_SUCCESS(Status))
{
ServiceLocator::LocateGlobals().ntstatusConsoleInputInitStatus = Status;

View File

@@ -67,9 +67,8 @@ using namespace Microsoft::Console::Types;
auto& g = ServiceLocator::LocateGlobals();
auto& gci = g.getConsoleInformation();
LRESULT Status = 0;
auto Unlock = TRUE;
LockConsole();
const auto lock = LockConsole();
auto& ScreenInfo = GetScreenInfo();
if (hWnd == nullptr) // TODO: this might not be possible anymore
@@ -84,7 +83,6 @@ using namespace Microsoft::Console::Types;
Status = DefWindowProcW(hWnd, Message, wParam, lParam);
}
UnlockConsole();
return Status;
}
@@ -214,7 +212,6 @@ using namespace Microsoft::Console::Types;
pSuggestionSize->cy = rectProposed.height();
// Format our final suggestion for consumption.
UnlockConsole();
return TRUE;
}
@@ -476,9 +473,6 @@ using namespace Microsoft::Console::Types;
{
auto hHeirMenu = Menu::s_GetHeirMenuHandle();
Unlock = FALSE;
UnlockConsole();
TrackPopupMenuEx(hHeirMenu,
TPM_RIGHTBUTTON | (GetSystemMetrics(SM_MENUDROPALIGNMENT) == 0 ? TPM_LEFTALIGN : TPM_RIGHTALIGN),
GET_X_LPARAM(lParam),
@@ -499,8 +493,6 @@ using namespace Microsoft::Console::Types;
switch (wParam & 0x00FF)
{
case HTCAPTION:
UnlockConsole();
Unlock = FALSE;
SetActiveWindow(hWnd);
SendMessageTimeoutW(hWnd, WM_SYSCOMMAND, SC_MOVE | wParam, lParam, SMTO_NORMAL, INFINITE, nullptr);
break;
@@ -560,7 +552,6 @@ using namespace Microsoft::Console::Types;
else if (wParam == ID_CONSOLE_FIND)
{
DoFind();
Unlock = FALSE;
}
else if (wParam == ID_CONSOLE_SELECTALL)
{
@@ -670,9 +661,6 @@ using namespace Microsoft::Console::Types;
case CM_BEEP:
{
UnlockConsole();
Unlock = FALSE;
// Don't fall back to Beep() on win32 systems -- if the user configures their system for no sound, we should
// respect that.
PlaySoundW((LPCWSTR)SND_ALIAS_SYSTEMHAND, nullptr, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
@@ -752,21 +740,11 @@ using namespace Microsoft::Console::Types;
default:
CallDefWin:
{
if (Unlock)
{
UnlockConsole();
Unlock = FALSE;
}
Status = DefWindowProcW(hWnd, Message, wParam, lParam);
break;
}
}
if (Unlock)
{
UnlockConsole();
}
return Status;
}

View File

@@ -109,70 +109,68 @@ try
{
FAIL_FAST_IF_NULL(pEngine); // This is a programming error. Fail fast.
_pData->LockConsole();
auto unlock = wil::scope_exit([&]() {
_pData->UnlockConsole();
});
// Last chance check if anything scrolled without an explicit invalidate notification since the last frame.
_CheckViewportAndScroll();
// Try to start painting a frame
const auto hr = pEngine->StartPaint();
RETURN_IF_FAILED(hr);
// Return early if there's nothing to paint.
// The renderer itself tracks if there's something to do with the title, the
// engine won't know that.
if (S_FALSE == hr)
{
return S_OK;
}
const auto lock = _pData->LockConsole();
auto endPaint = wil::scope_exit([&]() {
LOG_IF_FAILED(pEngine->EndPaint());
// Last chance check if anything scrolled without an explicit invalidate notification since the last frame.
_CheckViewportAndScroll();
// If the engine tells us it really wants to redraw immediately,
// tell the thread so it doesn't go to sleep and ticks again
// at the next opportunity.
if (pEngine->RequiresContinuousRedraw())
// Try to start painting a frame
const auto hr = pEngine->StartPaint();
RETURN_IF_FAILED(hr);
// Return early if there's nothing to paint.
// The renderer itself tracks if there's something to do with the title, the
// engine won't know that.
if (S_FALSE == hr)
{
NotifyPaintFrame();
return S_OK;
}
});
// A. Prep Colors
RETURN_IF_FAILED(_UpdateDrawingBrushes(pEngine, {}, false, true));
auto endPaint = wil::scope_exit([&]() {
LOG_IF_FAILED(pEngine->EndPaint());
// B. Perform Scroll Operations
RETURN_IF_FAILED(_PerformScrolling(pEngine));
// If the engine tells us it really wants to redraw immediately,
// tell the thread so it doesn't go to sleep and ticks again
// at the next opportunity.
if (pEngine->RequiresContinuousRedraw())
{
NotifyPaintFrame();
}
});
// C. Prepare the engine with additional information before we start drawing.
RETURN_IF_FAILED(_PrepareRenderInfo(pEngine));
// A. Prep Colors
RETURN_IF_FAILED(_UpdateDrawingBrushes(pEngine, {}, false, true));
// 1. Paint Background
RETURN_IF_FAILED(_PaintBackground(pEngine));
// B. Perform Scroll Operations
RETURN_IF_FAILED(_PerformScrolling(pEngine));
// 2. Paint Rows of Text
_PaintBufferOutput(pEngine);
// C. Prepare the engine with additional information before we start drawing.
RETURN_IF_FAILED(_PrepareRenderInfo(pEngine));
// 3. Paint overlays that reside above the text buffer
_PaintOverlays(pEngine);
// 1. Paint Background
RETURN_IF_FAILED(_PaintBackground(pEngine));
// 4. Paint Selection
_PaintSelection(pEngine);
// 2. Paint Rows of Text
_PaintBufferOutput(pEngine);
// 5. Paint Cursor
_PaintCursor(pEngine);
// 3. Paint overlays that reside above the text buffer
_PaintOverlays(pEngine);
// 6. Paint window title
RETURN_IF_FAILED(_PaintTitle(pEngine));
// 4. Paint Selection
_PaintSelection(pEngine);
// Force scope exit end paint to finish up collecting information and possibly painting
endPaint.reset();
// 5. Paint Cursor
_PaintCursor(pEngine);
// Force scope exit unlock to let go of global lock so other threads can run
unlock.reset();
// 6. Paint window title
RETURN_IF_FAILED(_PaintTitle(pEngine));
// Force scope exit end paint to finish up collecting information and possibly painting
endPaint.reset();
// Force scope exit unlock to let go of global lock so other threads can run
}
// Trigger out-of-lock presentation for renderers that can support it
RETURN_IF_FAILED(pEngine->Present());

View File

@@ -35,8 +35,7 @@ using Microsoft::Console::Interactivity::ServiceLocator;
a->dwProcessCount = BufferSize / sizeof(ULONG);
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
/*
* If there's not enough space in the array to hold all the pids, we'll
@@ -73,8 +72,7 @@ using Microsoft::Console::Interactivity::ServiceLocator;
const auto a = &m->u.consoleMsgL2.GenerateConsoleCtrlEvent;
Telemetry::Instance().LogApiCall(Telemetry::ApiCall::GenerateConsoleCtrlEvent);
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
const auto lock = LockConsole();
// Make sure the process group id is valid.
if (a->ProcessGroupId != 0)

View File

@@ -47,7 +47,7 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleCreateObject(_In_ PCONSOLE_API_MSG pMessa
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
const auto CreateInformation = &pMessage->CreateObject;
LockConsole();
const auto lock = LockConsole();
// If a generic object was requested, use the desired access to determine which type of object the caller is expecting.
if (CreateInformation->ObjectType == CD_IO_OBJECT_TYPE_GENERIC)
@@ -92,7 +92,6 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleCreateObject(_In_ PCONSOLE_API_MSG pMessa
if (!NT_SUCCESS(Status))
{
UnlockConsole();
pMessage->SetReplyStatus(Status);
return pMessage;
}
@@ -109,8 +108,6 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleCreateObject(_In_ PCONSOLE_API_MSG pMessa
handle.release();
}
UnlockConsole();
return nullptr;
}
@@ -122,12 +119,11 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleCreateObject(_In_ PCONSOLE_API_MSG pMessa
// - A pointer to the reply message.
PCONSOLE_API_MSG IoDispatchers::ConsoleCloseObject(_In_ PCONSOLE_API_MSG pMessage)
{
LockConsole();
const auto lock = LockConsole();
delete pMessage->GetObjectHandle();
pMessage->SetReplyStatus(STATUS_SUCCESS);
UnlockConsole();
return pMessage;
}
@@ -401,8 +397,7 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
ConsoleProcessHandle* ProcessData = nullptr;
NTSTATUS Status;
LockConsole();
const auto lock = LockConsole();
const auto cleanup = wil::scope_exit([&]() noexcept {
if (!NT_SUCCESS(Status))
{
@@ -413,9 +408,6 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
gci.ProcessHandleList.FreeProcessData(ProcessData);
}
}
// FreeProcessData() above requires the console to be locked.
UnlockConsole();
});
const auto dwProcessId = (DWORD)pReceiveMsg->Descriptor.Process;

View File

@@ -14,8 +14,9 @@ Author(s):
#pragma once
#include "inc/viewport.hpp"
#include <til/ticket_lock.h>
#include "../renderer/inc/FontInfo.hpp"
#include "inc/viewport.hpp"
class TextBuffer;
@@ -41,8 +42,7 @@ namespace Microsoft::Console::Types
virtual std::vector<Microsoft::Console::Types::Viewport> GetSelectionRects() noexcept = 0;
virtual void LockConsole() noexcept = 0;
virtual void UnlockConsole() noexcept = 0;
virtual [[nodiscard]] std::unique_lock<til::ticket_lock> LockConsole() noexcept = 0;
};
// See docs/virtual-dtors.md for an explanation of why this is weird.

View File

@@ -223,10 +223,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_
RETURN_HR_IF_NULL(E_INVALIDARG, ppRetVal);
*ppRetVal = nullptr;
_LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
// make a safe array
@@ -273,10 +270,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetVisibleRanges(_Outptr_result_mayben
RETURN_HR_IF_NULL(E_INVALIDARG, ppRetVal);
*ppRetVal = nullptr;
_LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
// make a safe array
@@ -379,15 +373,3 @@ Viewport ScreenInfoUiaProviderBase::_getViewport() const noexcept
{
return _pData->GetViewport();
}
void ScreenInfoUiaProviderBase::_LockConsole() noexcept
{
// TODO GitHub #2141: Lock and Unlock in conhost should decouple Ctrl+C dispatch and use smarter handling
_pData->LockConsole();
}
void ScreenInfoUiaProviderBase::_UnlockConsole() noexcept
{
// TODO GitHub #2141: Lock and Unlock in conhost should decouple Ctrl+C dispatch and use smarter handling
_pData->UnlockConsole();
}

View File

@@ -126,7 +126,5 @@ namespace Microsoft::Console::Types
til::size _getScreenBufferCoords() const noexcept;
const TextBuffer& _getTextBuffer() const noexcept;
Viewport _getViewport() const noexcept;
void _LockConsole() noexcept;
void _UnlockConsole() noexcept;
};
}

View File

@@ -202,10 +202,7 @@ bool UiaTextRangeBase::IsDegenerate() const noexcept
IFACEMETHODIMP UiaTextRangeBase::Compare(_In_opt_ ITextRangeProvider* pRange, _Out_ BOOL* pRetVal) noexcept
{
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_INVALIDARG, pRetVal == nullptr);
*pRetVal = FALSE;
@@ -229,10 +226,7 @@ try
RETURN_HR_IF_NULL(E_INVALIDARG, pRetVal);
*pRetVal = 0;
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
// get the text range that we're comparing to
@@ -261,10 +255,7 @@ CATCH_RETURN();
IFACEMETHODIMP UiaTextRangeBase::ExpandToEnclosingUnit(_In_ TextUnit unit) noexcept
{
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
try
@@ -451,10 +442,7 @@ try
RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr);
*ppRetVal = nullptr;
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
// AttributeIDs that require special handling
@@ -619,10 +607,7 @@ try
RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr);
*ppRetVal = nullptr;
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
const std::wstring queryText{ text, SysStringLen(text) };
@@ -750,10 +735,7 @@ try
RETURN_HR_IF(E_INVALIDARG, pRetVal == nullptr);
VariantInit(pRetVal);
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
// AttributeIDs that require special handling
@@ -847,10 +829,7 @@ IFACEMETHODIMP UiaTextRangeBase::GetBoundingRectangles(_Outptr_result_maybenull_
RETURN_HR_IF(E_INVALIDARG, ppRetVal == nullptr);
*ppRetVal = nullptr;
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
try
@@ -958,14 +937,12 @@ try
RETURN_HR_IF(E_INVALIDARG, maxLength < -1);
*pRetVal = nullptr;
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
const auto text = _getTextValue(maxLength);
Unlock.reset();
std::wstring text;
{
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
text = _getTextValue(maxLength);
}
*pRetVal = SysAllocString(text.c_str());
RETURN_HR_IF_NULL(E_OUTOFMEMORY, *pRetVal);
@@ -1030,10 +1007,7 @@ try
RETURN_HR_IF(E_INVALIDARG, pRetVal == nullptr);
*pRetVal = 0;
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
// We can abstract this movement by moving _start
@@ -1098,10 +1072,7 @@ IFACEMETHODIMP UiaTextRangeBase::MoveEndpointByUnit(_In_ TextPatternRangeEndpoin
RETURN_HR_IF(E_INVALIDARG, pRetVal == nullptr);
*pRetVal = 0;
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
RETURN_HR_IF(S_OK, count == 0);
@@ -1155,10 +1126,7 @@ IFACEMETHODIMP UiaTextRangeBase::MoveEndpointByRange(_In_ TextPatternRangeEndpoi
_In_ TextPatternRangeEndpoint targetEndpoint) noexcept
try
{
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
const UiaTextRangeBase* range = static_cast<UiaTextRangeBase*>(pTargetRange);
RETURN_HR_IF_NULL(E_INVALIDARG, range);
@@ -1182,10 +1150,7 @@ CATCH_RETURN();
IFACEMETHODIMP UiaTextRangeBase::Select() noexcept
try
{
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
const auto lock = _pData->LockConsole();
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
if (IsDegenerate())
@@ -1224,70 +1189,69 @@ IFACEMETHODIMP UiaTextRangeBase::RemoveFromSelection() noexcept
IFACEMETHODIMP UiaTextRangeBase::ScrollIntoView(_In_ BOOL alignToTop) noexcept
try
{
_pData->LockConsole();
auto Unlock = wil::scope_exit([&]() noexcept {
_pData->UnlockConsole();
});
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
const auto lock = _pData->LockConsole();
const auto oldViewport = _pData->GetViewport().ToInclusive();
const auto viewportHeight = _getViewportHeight(oldViewport);
// range rows
const auto startScreenInfoRow = _start.Y;
const auto endScreenInfoRow = _end.Y;
// screen buffer rows
const til::CoordType topRow = 0;
const auto bottomRow = _pData->GetTextBuffer().TotalRowCount() - 1;
auto newViewport = oldViewport;
// there's a bunch of +1/-1s here for setting the viewport. These
// are to account for the inclusivity of the viewport boundaries.
if (alignToTop)
til::inclusive_rect newViewport;
{
// determine if we can align the start row to the top
if (startScreenInfoRow + viewportHeight <= bottomRow)
RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());
const auto oldViewport = _pData->GetViewport().ToInclusive();
const auto viewportHeight = _getViewportHeight(oldViewport);
// range rows
const auto startScreenInfoRow = _start.Y;
const auto endScreenInfoRow = _end.Y;
// screen buffer rows
const til::CoordType topRow = 0;
const auto bottomRow = _pData->GetTextBuffer().TotalRowCount() - 1;
newViewport = oldViewport;
// there's a bunch of +1/-1s here for setting the viewport. These
// are to account for the inclusivity of the viewport boundaries.
if (alignToTop)
{
// we can align to the top
newViewport.Top = startScreenInfoRow;
newViewport.Bottom = startScreenInfoRow + viewportHeight - 1;
// determine if we can align the start row to the top
if (startScreenInfoRow + viewportHeight <= bottomRow)
{
// we can align to the top
newViewport.Top = startScreenInfoRow;
newViewport.Bottom = startScreenInfoRow + viewportHeight - 1;
}
else
{
// we can't align to the top so we'll just move the viewport
// to the bottom of the screen buffer
newViewport.Bottom = bottomRow;
newViewport.Top = bottomRow - viewportHeight + 1;
}
}
else
{
// we can't align to the top so we'll just move the viewport
// to the bottom of the screen buffer
newViewport.Bottom = bottomRow;
newViewport.Top = bottomRow - viewportHeight + 1;
// we need to align to the bottom
// check if we can align to the bottom
if (endScreenInfoRow >= viewportHeight)
{
// GH#7839: endScreenInfoRow may be ExclusiveEnd
// ExclusiveEnd is past the bottomRow
// so we need to clamp to the bottom row to stay in bounds
// we can align to bottom
newViewport.Bottom = std::min(endScreenInfoRow, bottomRow);
newViewport.Top = newViewport.Bottom - viewportHeight + 1;
}
else
{
// we can't align to bottom so we'll move the viewport to
// the top of the screen buffer
newViewport.Top = topRow;
newViewport.Bottom = topRow + viewportHeight - 1;
}
}
assert(newViewport.Top >= topRow);
assert(newViewport.Bottom <= bottomRow);
assert(_getViewportHeight(oldViewport) == _getViewportHeight(newViewport));
}
else
{
// we need to align to the bottom
// check if we can align to the bottom
if (endScreenInfoRow >= viewportHeight)
{
// GH#7839: endScreenInfoRow may be ExclusiveEnd
// ExclusiveEnd is past the bottomRow
// so we need to clamp to the bottom row to stay in bounds
// we can align to bottom
newViewport.Bottom = std::min(endScreenInfoRow, bottomRow);
newViewport.Top = newViewport.Bottom - viewportHeight + 1;
}
else
{
// we can't align to bottom so we'll move the viewport to
// the top of the screen buffer
newViewport.Top = topRow;
newViewport.Bottom = topRow + viewportHeight - 1;
}
}
assert(newViewport.Top >= topRow);
assert(newViewport.Bottom <= bottomRow);
assert(_getViewportHeight(oldViewport) == _getViewportHeight(newViewport));
Unlock.reset();
const gsl::not_null<ScreenInfoUiaProviderBase*> provider = static_cast<ScreenInfoUiaProviderBase*>(_pProvider);
provider->ChangeViewport(newViewport);