mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-20 21:22:47 +00:00
Compare commits
9 Commits
dev/duhowe
...
dev/lhecke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79e9f114d7 | ||
|
|
7f53e12060 | ||
|
|
8f346a7158 | ||
|
|
437b5ac595 | ||
|
|
feed768b3f | ||
|
|
937cadcad0 | ||
|
|
9aee510ce0 | ||
|
|
c9aeea1fdc | ||
|
|
6b4b63b18a |
15
.git-blame-ignore-revs
Normal file
15
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,15 @@
|
||||
# Commits mentioned in this file will automatically
|
||||
# be skipped by GitHub's blame view.
|
||||
# To use it with "git", run
|
||||
# > git blame --ignore-revs-file ./.git-blame-ignore-revs
|
||||
|
||||
# Reformatted the entire codebase
|
||||
9b92986b49bed8cc41fde4d6ef080921c41e6d9e
|
||||
|
||||
# Line Endings changes
|
||||
cb7a76d96c92aa9fc7b03f69148fb0c75dff191d
|
||||
5bbf61af8c8f12e6c05d07a696bf7d411b330a67
|
||||
d07546a6fef73fa4e1fb1c2f01535843d1fcc212
|
||||
|
||||
# UTF-8 BOM changes
|
||||
ddae2a1d49d604487d3c963e5eacbeb73861d986
|
||||
2
.github/ISSUE_TEMPLATE/Bug_Report.yml
vendored
2
.github/ISSUE_TEMPLATE/Bug_Report.yml
vendored
@@ -14,7 +14,7 @@ body:
|
||||
label: Windows Terminal version
|
||||
placeholder: "1.7.3651.0"
|
||||
description: |
|
||||
You can find the version in the about dialog, or by running `wt -v` at the commandline (for the Stable/Preview version you’re reporting a bug about).
|
||||
You can copy the version number from the About dialog. Open the About dialog by opening the menu with the "V" button (to the right of the "+" button that opens a new tab) and choosing About from the end of the list.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
|
||||
1
.github/actions/spelling/README.md
vendored
1
.github/actions/spelling/README.md
vendored
@@ -6,6 +6,7 @@ File | Purpose | Format | Info
|
||||
[reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject)
|
||||
[excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes)
|
||||
[patterns/*.txt](patterns/) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
|
||||
[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns)
|
||||
[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
|
||||
[expect/*.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect)
|
||||
[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice)
|
||||
|
||||
2
.github/actions/spelling/advice.md
vendored
2
.github/actions/spelling/advice.md
vendored
@@ -21,7 +21,7 @@ See the `README.md` in each directory for more information.
|
||||
:microscope: You can test your commits **without** *appending* to a PR by creating a new branch with that extra change and pushing it to your fork. The [check-spelling](https://github.com/marketplace/actions/check-spelling) action will run in response to your **push** -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. :wink:
|
||||
|
||||
|
||||
<details><summary>:clamp: If the flagged items are false positives</summary>
|
||||
<details><summary>If the flagged items are :exploding_head: false positives</summary>
|
||||
|
||||
If items relate to a ...
|
||||
* binary file (or some other file you wouldn't want to check at all).
|
||||
|
||||
8
.github/actions/spelling/allow/allow.txt
vendored
8
.github/actions/spelling/allow/allow.txt
vendored
@@ -1,7 +1,7 @@
|
||||
admins
|
||||
allcolors
|
||||
apc
|
||||
Apc
|
||||
apc
|
||||
breadcrumb
|
||||
breadcrumbs
|
||||
bsd
|
||||
@@ -14,8 +14,8 @@ CMMI
|
||||
copyable
|
||||
cybersecurity
|
||||
dalet
|
||||
dcs
|
||||
Dcs
|
||||
dcs
|
||||
dialytika
|
||||
dje
|
||||
downside
|
||||
@@ -34,10 +34,12 @@ gantt
|
||||
gcc
|
||||
geeksforgeeks
|
||||
ghe
|
||||
github
|
||||
gje
|
||||
godbolt
|
||||
hostname
|
||||
hostnames
|
||||
https
|
||||
hyperlink
|
||||
hyperlinking
|
||||
hyperlinks
|
||||
@@ -82,6 +84,7 @@ runtimes
|
||||
shcha
|
||||
slnt
|
||||
Sos
|
||||
ssh
|
||||
timeline
|
||||
timelines
|
||||
timestamped
|
||||
@@ -90,6 +93,7 @@ tokenizes
|
||||
tonos
|
||||
toolset
|
||||
tshe
|
||||
ubuntu
|
||||
uiatextrange
|
||||
UIs
|
||||
und
|
||||
|
||||
523
.github/actions/spelling/candidate.patterns
vendored
Normal file
523
.github/actions/spelling/candidate.patterns
vendored
Normal file
@@ -0,0 +1,523 @@
|
||||
# marker to ignore all code on line
|
||||
^.*/\* #no-spell-check-line \*/.*$
|
||||
# marker for ignoring a comment to the end of the line
|
||||
// #no-spell-check.*$
|
||||
|
||||
# patch hunk comments
|
||||
^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .*
|
||||
# git index header
|
||||
index [0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
|
||||
|
||||
# cid urls
|
||||
(['"])cid:.*?\g{-1}
|
||||
|
||||
# data url in parens
|
||||
\(data:[^)]*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})[^)]*\)
|
||||
# data url in quotes
|
||||
([`'"])data:.*?(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1}
|
||||
# data url
|
||||
data:[-a-zA-Z=;:/0-9+]*,\S*
|
||||
|
||||
# mailto urls
|
||||
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
|
||||
|
||||
# magnet urls
|
||||
magnet:[?=:\w]+
|
||||
|
||||
# magnet urls
|
||||
"magnet:[^"]+"
|
||||
|
||||
# obs:
|
||||
"obs:[^"]*"
|
||||
|
||||
# The `\b` here means a break, it's the fancy way to handle urls, but it makes things harder to read
|
||||
# In this examples content, I'm using a number of different ways to match things to show various approaches
|
||||
# asciinema
|
||||
\basciinema\.org/a/[0-9a-zA-Z]+
|
||||
|
||||
# apple
|
||||
\bdeveloper\.apple\.com/[-\w?=/]+
|
||||
# Apple music
|
||||
\bembed\.music\.apple\.com/fr/playlist/usr-share/[-\w.]+
|
||||
|
||||
# appveyor api
|
||||
\bci\.appveyor\.com/api/projects/status/[0-9a-z]+
|
||||
# appveyor project
|
||||
\bci\.appveyor\.com/project/(?:[^/\s"]*/){2}builds?/\d+/job/[0-9a-z]+
|
||||
|
||||
# Amazon
|
||||
|
||||
# Amazon
|
||||
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
|
||||
# AWS S3
|
||||
\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]*
|
||||
# AWS execute-api
|
||||
\b[0-9a-z]{10}\.execute-api\.[-0-9a-z]+\.amazonaws\.com\b
|
||||
# AWS ELB
|
||||
\b\w+\.[-0-9a-z]+\.elb\.amazonaws\.com\b
|
||||
# AWS SNS
|
||||
\bsns\.[-0-9a-z]+.amazonaws\.com/[-\w/&#%_?:=]*
|
||||
# AWS VPC
|
||||
vpc-\w+
|
||||
|
||||
# While you could try to match `http://` and `https://` by using `s?` in `https?://`, sometimes there
|
||||
# YouTube url
|
||||
\b(?:(?:www\.|)youtube\.com|youtu.be)/(?:channel/|embed/|user/|playlist\?list=|watch\?v=|v/|)[-a-zA-Z0-9?&=_%]*
|
||||
# YouTube music
|
||||
\bmusic\.youtube\.com/youtubei/v1/browse(?:[?&]\w+=[-a-zA-Z0-9?&=_]*)
|
||||
# YouTube tag
|
||||
<\s*youtube\s+id=['"][-a-zA-Z0-9?_]*['"]
|
||||
# YouTube image
|
||||
\bimg\.youtube\.com/vi/[-a-zA-Z0-9?&=_]*
|
||||
# Google Accounts
|
||||
\baccounts.google.com/[-_/?=.:;+%&0-9a-zA-Z]*
|
||||
# Google Analytics
|
||||
\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]*
|
||||
# Google APIs
|
||||
\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+
|
||||
# Google Storage
|
||||
\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|)
|
||||
# Google Calendar
|
||||
\bcalendar\.google\.com/calendar(?:/u/\d+|)/embed\?src=[@./?=\w&%]+
|
||||
\w+\@group\.calendar\.google\.com\b
|
||||
# Google DataStudio
|
||||
\bdatastudio\.google\.com/(?:(?:c/|)u/\d+/|)(?:embed/|)(?:open|reporting|datasources|s)/[-0-9a-zA-Z]+(?:/page/[-0-9a-zA-Z]+|)
|
||||
# The leading `/` here is as opposed to the `\b` above
|
||||
# ... a short way to match `https://` or `http://` since most urls have one of those prefixes
|
||||
# Google Docs
|
||||
/docs\.google\.com/[a-z]+/(?:ccc\?key=\w+|(?:u/\d+|d/(?:e/|)[0-9a-zA-Z_-]+/)?(?:edit\?[-\w=#.]*|/\?[\w=&]*|))
|
||||
# Google Drive
|
||||
\bdrive\.google\.com/(?:file/d/|open)[-0-9a-zA-Z_?=]*
|
||||
# Google Groups
|
||||
\bgroups\.google\.com/(?:(?:forum/#!|d/)(?:msg|topics?|searchin)|a)/[^/\s"]+/[-a-zA-Z0-9$]+(?:/[-a-zA-Z0-9]+)*
|
||||
# Google Maps
|
||||
\bmaps\.google\.com/maps\?[\w&;=]*
|
||||
# Google themes
|
||||
themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
|
||||
# Google CDN
|
||||
\bclients2\.google(?:usercontent|)\.com[-0-9a-zA-Z/.]*
|
||||
# Goo.gl
|
||||
/goo\.gl/[a-zA-Z0-9]+
|
||||
# Google Chrome Store
|
||||
\bchrome\.google\.com/webstore/detail/[-\w]*(?:/\w*|)
|
||||
# Google Books
|
||||
\bgoogle\.(?:\w{2,4})/books(?:/\w+)*\?[-\w\d=&#.]*
|
||||
# Google Fonts
|
||||
\bfonts\.(?:googleapis|gstatic)\.com/[-/?=:;+&0-9a-zA-Z]*
|
||||
# Google Forms
|
||||
\bforms\.gle/\w+
|
||||
# Google Scholar
|
||||
\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+
|
||||
# Google Colab Research Drive
|
||||
\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]*
|
||||
|
||||
# GitHub SHAs (api)
|
||||
\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b
|
||||
# GitHub SHAs (markdown)
|
||||
(?:\[`?[0-9a-f]+`?\]\(https:/|)/(?:www\.|)github\.com(?:/[^/\s"]+){2,}(?:/[^/\s")]+)(?:[0-9a-f]+(?:[-0-9a-zA-Z/#.]*|)\b|)
|
||||
# GitHub SHAs
|
||||
\bgithub\.com(?:/[^/\s"]+){2}[@#][0-9a-f]+\b
|
||||
# GitHub wiki
|
||||
\bgithub\.com/(?:[^/]+/){2}wiki/(?:(?:[^/]+/|)_history|[^/]+(?:/_compare|)/[0-9a-f.]{40,})\b
|
||||
# githubusercontent
|
||||
/[-a-z0-9]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
|
||||
# githubassets
|
||||
\bgithubassets.com/[0-9a-f]+(?:[-/\w.]+)
|
||||
# gist github
|
||||
\bgist\.github\.com/[^/\s"]+/[0-9a-f]+
|
||||
# git.io
|
||||
\bgit\.io/[0-9a-zA-Z]+
|
||||
# GitHub JSON
|
||||
"node_id": "[-a-zA-Z=;:/0-9+]*"
|
||||
# Contributor
|
||||
\[[^\]]+\]\(https://github\.com/[^/\s"]+\)
|
||||
# GHSA
|
||||
GHSA(?:-[0-9a-z]{4}){3}
|
||||
|
||||
# GitLab commit
|
||||
\bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b
|
||||
# GitLab merge requests
|
||||
\bgitlab\.[^/\s"]*/\S+/\S+/-/merge_requests/\d+/diffs#[0-9a-f]{40}\b
|
||||
# GitLab uploads
|
||||
\bgitlab\.[^/\s"]*/uploads/[-a-zA-Z=;:/0-9+]*
|
||||
# GitLab commits
|
||||
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
|
||||
|
||||
# binanace
|
||||
accounts.binance.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
|
||||
|
||||
# bitbucket diff
|
||||
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}diff(?:stat|)(?:/[^/\s"]+){2}:[0-9a-f]+
|
||||
# bitbucket repositories commits
|
||||
\bapi\.bitbucket\.org/\d+\.\d+/repositories/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
|
||||
# bitbucket commits
|
||||
\bbitbucket\.org/(?:[^/\s"]+/){2}commits?/[0-9a-f]+
|
||||
|
||||
# bit.ly
|
||||
\bbit\.ly/\w+
|
||||
|
||||
# bitrise
|
||||
\bapp\.bitrise\.io/app/[0-9a-f]*/[\w.?=&]*
|
||||
|
||||
# bootstrapcdn.com
|
||||
\bbootstrapcdn\.com/[-./\w]+
|
||||
|
||||
# cdn.cloudflare.com
|
||||
\bcdnjs\.cloudflare\.com/[./\w]+
|
||||
|
||||
# circleci
|
||||
\bcircleci\.com/gh(?:/[^/\s"]+){1,5}.[a-z]+\?[-0-9a-zA-Z=&]+
|
||||
|
||||
# gitter
|
||||
\bgitter\.im(?:/[^/\s"]+){2}\?at=[0-9a-f]+
|
||||
|
||||
# gravatar
|
||||
\bgravatar\.com/avatar/[0-9a-f]+
|
||||
|
||||
# ibm
|
||||
[a-z.]*ibm\.com/[-_#=:%!?~.\\/\d\w]*
|
||||
|
||||
# imgur
|
||||
\bimgur\.com/[^.]+
|
||||
|
||||
# Internet Archive
|
||||
\barchive\.org/web/\d+/(?:[-\w.?,'/\\+&%$#_:]*)
|
||||
|
||||
# discord
|
||||
/discord(?:app\.com|\.gg)/(?:invite/)?[a-zA-Z0-9]{7,}
|
||||
|
||||
# Disqus
|
||||
\bdisqus\.com/[-\w/%.()!?&=_]*
|
||||
|
||||
# medium link
|
||||
\blink\.medium\.com/[a-zA-Z0-9]+
|
||||
# medium
|
||||
\bmedium\.com/\@?[^/\s"]+/[-\w]+
|
||||
|
||||
# microsoft
|
||||
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
|
||||
# powerbi
|
||||
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
|
||||
# vs devops
|
||||
\bvisualstudio.com(?::443|)/[-\w/?=%&.]*
|
||||
# microsoft store
|
||||
\bmicrosoft\.com/store/apps/\w+
|
||||
|
||||
# mvnrepository.com
|
||||
\bmvnrepository\.com/[-0-9a-z./]+
|
||||
|
||||
# now.sh
|
||||
/[0-9a-z-.]+\.now\.sh\b
|
||||
|
||||
# oracle
|
||||
\bdocs\.oracle\.com/[-0-9a-zA-Z./_?#&=]*
|
||||
|
||||
# chromatic.com
|
||||
/\S+.chromatic.com\S*[")]
|
||||
|
||||
# codacy
|
||||
\bapi\.codacy\.com/project/badge/Grade/[0-9a-f]+
|
||||
|
||||
# compai
|
||||
\bcompai\.pub/v1/png/[0-9a-f]+
|
||||
|
||||
# mailgun api
|
||||
\.api\.mailgun\.net/v3/domains/[0-9a-z]+\.mailgun.org/messages/[0-9a-zA-Z=@]*
|
||||
# mailgun
|
||||
\b[0-9a-z]+.mailgun.org
|
||||
|
||||
# /message-id/
|
||||
/message-id/[-\w@./%]+
|
||||
|
||||
# Reddit
|
||||
\breddit\.com/r/[/\w_]*
|
||||
|
||||
# requestb.in
|
||||
\brequestb\.in/[0-9a-z]+
|
||||
|
||||
# sched
|
||||
\b[a-z0-9]+\.sched\.com\b
|
||||
|
||||
# Slack url
|
||||
slack://[a-zA-Z0-9?&=]+
|
||||
# Slack
|
||||
\bslack\.com/[-0-9a-zA-Z/_~?&=.]*
|
||||
# Slack edge
|
||||
\bslack-edge\.com/[-a-zA-Z0-9?&=%./]+
|
||||
# Slack images
|
||||
\bslack-imgs\.com/[-a-zA-Z0-9?&=%.]+
|
||||
|
||||
# shields.io
|
||||
\bshields\.io/[-\w/%?=&.:+;,]*
|
||||
|
||||
# stackexchange -- https://stackexchange.com/feeds/sites
|
||||
\b(?:askubuntu|serverfault|stack(?:exchange|overflow)|superuser).com/(?:questions/\w+/[-\w]+|a/)
|
||||
|
||||
# Sentry
|
||||
[0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b
|
||||
|
||||
# Twitter markdown
|
||||
\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\)
|
||||
# Twitter hashtag
|
||||
\btwitter\.com/hashtag/[\w?_=&]*
|
||||
# Twitter status
|
||||
\btwitter\.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)
|
||||
# Twitter profile images
|
||||
\btwimg\.com/profile_images/[_\w./]*
|
||||
# Twitter media
|
||||
\btwimg\.com/media/[-_\w./?=]*
|
||||
# Twitter link shortened
|
||||
\bt\.co/\w+
|
||||
|
||||
# facebook
|
||||
\bfburl\.com/[0-9a-z_]+
|
||||
# facebook CDN
|
||||
\bfbcdn\.net/[\w/.,]*
|
||||
# facebook watch
|
||||
\bfb\.watch/[0-9A-Za-z]+
|
||||
|
||||
# dropbox
|
||||
\bdropbox\.com/sh?/[^/\s"]+/[-0-9A-Za-z_.%?=&;]+
|
||||
|
||||
# ipfs protocol
|
||||
ipfs://[0-9a-z]*
|
||||
# ipfs url
|
||||
/ipfs/[0-9a-z]*
|
||||
|
||||
# w3
|
||||
\bw3\.org/[-0-9a-zA-Z/#.]+
|
||||
|
||||
# loom
|
||||
\bloom\.com/embed/[0-9a-f]+
|
||||
|
||||
# regex101
|
||||
\bregex101\.com/r/[^/\s"]+/\d+
|
||||
|
||||
# figma
|
||||
\bfigma\.com/file(?:/[0-9a-zA-Z]+/)+
|
||||
|
||||
# freecodecamp.org
|
||||
\bfreecodecamp\.org/[-\w/.]+
|
||||
|
||||
# image.tmdb.org
|
||||
\bimage\.tmdb\.org/[/\w.]+
|
||||
|
||||
# mermaid
|
||||
\bmermaid\.ink/img/[-\w]+|\bmermaid-js\.github\.io/mermaid-live-editor/#/edit/[-\w]+
|
||||
|
||||
# Wikipedia
|
||||
\ben\.wikipedia\.org/wiki/[-\w%.#]+
|
||||
|
||||
# gitweb
|
||||
[^"\s]+/gitweb/\S+;h=[0-9a-f]+
|
||||
|
||||
# HyperKitty lists
|
||||
/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/
|
||||
|
||||
# lists
|
||||
/thread\.html/[^"\s]+
|
||||
|
||||
# list-management
|
||||
\blist-manage\.com/subscribe(?:[?&](?:u|id)=[0-9a-f]+)+
|
||||
|
||||
# kubectl.kubernetes.io/last-applied-configuration
|
||||
"kubectl.kubernetes.io/last-applied-configuration": ".*"
|
||||
|
||||
# pgp
|
||||
\bgnupg\.net/pks/lookup[?&=0-9a-zA-Z]*
|
||||
|
||||
# Spotify
|
||||
\bopen\.spotify\.com/embed/playlist/\w+
|
||||
|
||||
# Mastodon
|
||||
\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]*
|
||||
|
||||
# scastie
|
||||
\bscastie\.scala-lang\.org/[^/]+/\w+
|
||||
|
||||
# images.unsplash.com
|
||||
\bimages\.unsplash\.com/(?:(?:flagged|reserve)/|)[-\w./%?=%&.;]+
|
||||
|
||||
# pastebin
|
||||
\bpastebin\.com/[\w/]+
|
||||
|
||||
# heroku
|
||||
\b\w+\.heroku\.com/source/archive/\w+
|
||||
|
||||
# quip
|
||||
\b\w+\.quip\.com/\w+(?:(?:#|/issues/)\w+)?
|
||||
|
||||
# badgen.net
|
||||
\bbadgen\.net/badge/[^")\]'\s]+
|
||||
|
||||
# statuspage.io
|
||||
\w+\.statuspage\.io\b
|
||||
|
||||
# media.giphy.com
|
||||
\bmedia\.giphy\.com/media/[^/]+/[\w.?&=]+
|
||||
|
||||
# tinyurl
|
||||
\btinyurl\.com/\w+
|
||||
|
||||
# getopts
|
||||
\bgetopts\s+(?:"[^"]+"|'[^']+')
|
||||
|
||||
# ANSI color codes
|
||||
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
|
||||
|
||||
# URL escaped characters
|
||||
\%[0-9A-F][A-F]
|
||||
# IPv6
|
||||
\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b
|
||||
# c99 hex digits (not the full format, just one I've seen)
|
||||
0x[0-9a-fA-F](?:\.[0-9a-fA-F]*|)[pP]
|
||||
# Punycode
|
||||
\bxn--[-0-9a-z]+
|
||||
# sha
|
||||
sha\d+:[0-9]*[a-f]{3,}[0-9a-f]*
|
||||
# sha-... -- uses a fancy capture
|
||||
(['"]|")[0-9a-f]{40,}\g{-1}
|
||||
# hex runs
|
||||
\b[0-9a-fA-F]{16,}\b
|
||||
# hex in url queries
|
||||
=[0-9a-fA-F]*?(?:[A-F]{3,}|[a-f]{3,})[0-9a-fA-F]*?&
|
||||
# ssh
|
||||
(?:ssh-\S+|-nistp256) [-a-zA-Z=;:/0-9+]{12,}
|
||||
|
||||
# PGP
|
||||
\b(?:[0-9A-F]{4} ){9}[0-9A-F]{4}\b
|
||||
# GPG keys
|
||||
\b(?:[0-9A-F]{4} ){5}(?: [0-9A-F]{4}){5}\b
|
||||
# Well known gpg keys
|
||||
.well-known/openpgpkey/[\w./]+
|
||||
|
||||
# uuid:
|
||||
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
|
||||
# hex digits including css/html color classes:
|
||||
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
|
||||
# integrity
|
||||
integrity="sha\d+-[-a-zA-Z=;:/0-9+]{40,}"
|
||||
|
||||
# https://www.gnu.org/software/groff/manual/groff.html
|
||||
# man troff content
|
||||
\\f[BCIPR]
|
||||
# '
|
||||
\\\(aq
|
||||
|
||||
# .desktop mime types
|
||||
^MimeTypes?=.*$
|
||||
# .desktop localized entries
|
||||
^[A-Z][a-z]+\[[a-z]+\]=.*$
|
||||
# Localized .desktop content
|
||||
Name\[[^\]]+\]=.*
|
||||
|
||||
# IServiceProvider
|
||||
\bI(?=(?:[A-Z][a-z]{2,})+\b)
|
||||
|
||||
# crypt
|
||||
"\$2[ayb]\$.{56}"
|
||||
|
||||
# scrypt / argon
|
||||
\$(?:scrypt|argon\d+[di]*)\$\S+
|
||||
|
||||
# Input to GitHub JSON
|
||||
content: "[-a-zA-Z=;:/0-9+]*="
|
||||
|
||||
# Python stringprefix / binaryprefix
|
||||
# Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings
|
||||
(?<!')\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})
|
||||
|
||||
# Regular expressions for (P|p)assword
|
||||
\([A-Z]\|[a-z]\)[a-z]+
|
||||
|
||||
# JavaScript regular expressions
|
||||
# javascript test regex
|
||||
/.*/[gim]*\.test\(
|
||||
# javascript match regex
|
||||
\.match\(/[^/\s"]*/[gim]*\s*
|
||||
# javascript match regex
|
||||
\.match\(/\\[b].*?/[gim]*\s*\)(?:;|$)
|
||||
# javascript regex
|
||||
^\s*/\\[b].*/[gim]*\s*(?:\)(?:;|$)|,$)
|
||||
# javascript replace regex
|
||||
\.replace\(/[^/\s"]*/[gim]*\s*,
|
||||
|
||||
# Go regular expressions
|
||||
regexp?\.MustCompile\(`[^`]*`\)
|
||||
|
||||
# sed regular expressions
|
||||
sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2}
|
||||
|
||||
# go install
|
||||
go install(?:\s+[a-z]+\.[-@\w/.]+)+
|
||||
|
||||
# kubernetes pod status lists
|
||||
# https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
|
||||
\w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+
|
||||
|
||||
# kubectl - pods in CrashLoopBackOff
|
||||
\w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+
|
||||
|
||||
# kubernetes object suffix
|
||||
-[0-9a-f]{10}-\w{5}\s
|
||||
|
||||
# posthog secrets
|
||||
posthog\.init\((['"])phc_[^"',]+\g{-1},
|
||||
|
||||
# xcode
|
||||
|
||||
# xcodeproject scenes
|
||||
(?:Controller|ID|id)="\w{3}-\w{2}-\w{3}"
|
||||
|
||||
# xcode api botches
|
||||
customObjectInstantitationMethod
|
||||
|
||||
# font awesome classes
|
||||
\.fa-[-a-z0-9]+
|
||||
|
||||
# Update Lorem based on your content (requires `ge` and `w` from https://github.com/jsoref/spelling; and `review` from https://github.com/check-spelling/check-spelling/wiki/Looking-for-items-locally )
|
||||
# grep '^[^#].*lorem' .github/actions/spelling/patterns.txt|perl -pne 's/.*i..\?://;s/\).*//' |tr '|' "\n"|sort -f |xargs -n1 ge|perl -pne 's/^[^:]*://'|sort -u|w|sed -e 's/ .*//'|w|review -
|
||||
# Warning, while `(?i)` is very neat and fancy, if you have some binary files that aren't proper unicode, you might run into:
|
||||
## Operation "substitution (s///)" returns its argument for non-Unicode code point 0x1C19AE (the code point will vary).
|
||||
## You could manually change `(?i)X...` to use `[Xx]...`
|
||||
## or you could add the files to your `excludes` file (a version after 0.0.19 should identify the file path)
|
||||
# Lorem
|
||||
(?:\w|\s|[,.])*\b(?i)(?:amet|consectetur|cursus|dolor|eros|ipsum|lacus|libero|ligula|lorem|magna|neque|nulla|suscipit|tempus)\b(?:\w|\s|[,.])*
|
||||
|
||||
# Non-English
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
|
||||
|
||||
# French
|
||||
# This corpus only had capital letters, but you probably want lowercase ones as well.
|
||||
\b[LN]'+[a-z]{2,}\b
|
||||
|
||||
# latex
|
||||
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
|
||||
|
||||
# the negative lookahead here is to allow catching 'templatesz' as a misspelling
|
||||
# but to otherwise recognize a Windows path with \templates\foo.template or similar:
|
||||
\\(?:necessary|r(?:eport|esolve[dr]?|esult)|t(?:arget|emplates?))(?![a-z])
|
||||
# ignore long runs of a single character:
|
||||
\b([A-Za-z])\g{-1}{3,}\b
|
||||
# Note that the next example is no longer necessary if you are using
|
||||
# to match a string starting with a `#`, use a character-class:
|
||||
[#]backwards
|
||||
# version suffix <word>v#
|
||||
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
|
||||
# Compiler flags (Scala)
|
||||
(?:^|[\t ,>"'`=(])-J-[DPWXY](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
# Compiler flags
|
||||
#(?:^|[\t ,"'`=(])-[DPWXYLlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
|
||||
# Compiler flags (linker)
|
||||
,-B
|
||||
# curl arguments
|
||||
\b(?:\\n|)curl(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
|
||||
# set arguments
|
||||
\bset(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)*
|
||||
# tar arguments
|
||||
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
|
||||
# tput arguments -- https://man7.org/linux/man-pages/man5/terminfo.5.html -- technically they can be more than 5 chars long...
|
||||
\btput\s+(?:(?:-[SV]|-T\s*\w+)\s+)*\w{3,5}\b
|
||||
# macOS temp folders
|
||||
/var/folders/\w\w/[+\w]+/(?:T|-Caches-)/
|
||||
38
.github/actions/spelling/excludes.txt
vendored
38
.github/actions/spelling/excludes.txt
vendored
@@ -2,14 +2,14 @@
|
||||
(?:(?i)\.png$)
|
||||
(?:^|/)(?i)COPYRIGHT
|
||||
(?:^|/)(?i)LICEN[CS]E
|
||||
(?:^|/)3rdparty/
|
||||
(?:^|/)dirs$
|
||||
(?:^|/)go\.mod$
|
||||
(?:^|/)go\.sum$
|
||||
(?:^|/)package(?:-lock|)\.json$
|
||||
(?:^|/)sources(?:|\.dep)$
|
||||
(?:^|/)vendor/
|
||||
ignore$
|
||||
SUMS$
|
||||
\.a$
|
||||
\.ai$
|
||||
\.avi$
|
||||
\.bmp$
|
||||
@@ -20,6 +20,8 @@ SUMS$
|
||||
\.crt$
|
||||
\.csr$
|
||||
\.dll$
|
||||
\.docx?$
|
||||
\.drawio$
|
||||
\.DS_Store$
|
||||
\.eot$
|
||||
\.eps$
|
||||
@@ -31,6 +33,7 @@ SUMS$
|
||||
\.icns$
|
||||
\.ico$
|
||||
\.jar$
|
||||
\.jks$
|
||||
\.jpeg$
|
||||
\.jpg$
|
||||
\.key$
|
||||
@@ -41,6 +44,7 @@ SUMS$
|
||||
\.mod$
|
||||
\.mp3$
|
||||
\.mp4$
|
||||
\.o$
|
||||
\.ocf$
|
||||
\.otf$
|
||||
\.pbxproj$
|
||||
@@ -48,22 +52,41 @@ SUMS$
|
||||
\.pem$
|
||||
\.png$
|
||||
\.psd$
|
||||
\.pyc$
|
||||
\.runsettings$
|
||||
\.s$
|
||||
\.sig$
|
||||
\.so$
|
||||
\.svg$
|
||||
\.svgz$
|
||||
\.svgz?$
|
||||
\.tar$
|
||||
\.tgz$
|
||||
\.tiff?$
|
||||
\.ttf$
|
||||
\.vsdx$
|
||||
\.wav$
|
||||
\.webm$
|
||||
\.webp$
|
||||
\.woff
|
||||
\.woff2?$
|
||||
\.xcf$
|
||||
\.xls
|
||||
\.xlsx?$
|
||||
\.xpm$
|
||||
\.yml$
|
||||
\.zip$
|
||||
^\.github/actions/spelling/
|
||||
^\.github/fabricbot.json$
|
||||
^\.gitignore$
|
||||
^\Q.git-blame-ignore-revs\E$
|
||||
^\Q.github/workflows/spelling.yml\E$
|
||||
^\Qdoc/reference/windows-terminal-logo.ans\E$
|
||||
^\Qsamples/ConPTY/EchoCon/EchoCon/EchoCon.vcxproj.filters\E$
|
||||
^\Qsrc/host/exe/Host.EXE.vcxproj.filters\E$
|
||||
^\Qsrc/host/ft_host/chafa.txt\E$
|
||||
^\Qsrc/tools/closetest/CloseTest.vcxproj.filters\E$
|
||||
^\XamlStyler.json$
|
||||
^build/config/
|
||||
^consolegit2gitfilters\.json$
|
||||
^dep/
|
||||
@@ -90,12 +113,5 @@ SUMS$
|
||||
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
|
||||
^src/types/ut_types/UtilsTests.cpp$
|
||||
^tools/ReleaseEngineering/ServicingPipeline.ps1$
|
||||
^\.github/actions/spelling/
|
||||
^\.github/fabricbot.json$
|
||||
^\.gitignore$
|
||||
^\Q.github/workflows/spelling.yml\E$
|
||||
^\Qsamples/ConPTY/EchoCon/EchoCon/EchoCon.vcxproj.filters\E$
|
||||
^\Qsrc/host/exe/Host.EXE.vcxproj.filters\E$
|
||||
^\Qsrc/host/ft_host/chafa.txt\E$
|
||||
^\Qsrc/tools/closetest/CloseTest.vcxproj.filters\E$
|
||||
^\XamlStyler.json$
|
||||
ignore$
|
||||
SUMS$
|
||||
|
||||
7
.github/actions/spelling/expect/alphabet.txt
vendored
7
.github/actions/spelling/expect/alphabet.txt
vendored
@@ -5,26 +5,19 @@ AAAAAABBBBBBCCC
|
||||
AAAAABBBBBBCCC
|
||||
abcd
|
||||
abcd
|
||||
abcde
|
||||
abcdef
|
||||
ABCDEFG
|
||||
ABCDEFGH
|
||||
ABCDEFGHIJ
|
||||
abcdefghijk
|
||||
ABCDEFGHIJKLMNO
|
||||
abcdefghijklmnop
|
||||
ABCDEFGHIJKLMNOPQRST
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
ABCG
|
||||
ABE
|
||||
abf
|
||||
BBBBB
|
||||
BBBBBBBB
|
||||
BBBBBBBBBBBBBBDDDD
|
||||
BBBBBCCC
|
||||
BBBBCCCCC
|
||||
BBGGRR
|
||||
CCE
|
||||
EFG
|
||||
EFGh
|
||||
QQQQQQQQQQABCDEFGHIJ
|
||||
|
||||
695
.github/actions/spelling/expect/expect.txt
vendored
695
.github/actions/spelling/expect/expect.txt
vendored
File diff suppressed because it is too large
Load Diff
2
.github/actions/spelling/expect/web.txt
vendored
2
.github/actions/spelling/expect/web.txt
vendored
@@ -1,5 +1,3 @@
|
||||
http
|
||||
www
|
||||
WCAG
|
||||
winui
|
||||
appshellintegration
|
||||
|
||||
30
.github/actions/spelling/line_forbidden.patterns
vendored
30
.github/actions/spelling/line_forbidden.patterns
vendored
@@ -1,3 +1,11 @@
|
||||
# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere
|
||||
# \bm_data\b
|
||||
|
||||
# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test,
|
||||
# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want
|
||||
# to use this:
|
||||
#\bfit\(
|
||||
|
||||
# s.b. GitHub
|
||||
\bGithub\b
|
||||
|
||||
@@ -16,6 +24,12 @@
|
||||
# s.b. greater than
|
||||
\bgreater then\b
|
||||
|
||||
# s.b. into
|
||||
#\sin to\s
|
||||
|
||||
# s.b. opt-in
|
||||
\sopt in\s
|
||||
|
||||
# s.b. less than
|
||||
\bless then\b
|
||||
|
||||
@@ -27,10 +41,22 @@
|
||||
\b[Nn]o[nt][- ]existent\b
|
||||
|
||||
# s.b. preexisting
|
||||
[Pp]re-existing
|
||||
[Pp]re[- ]existing
|
||||
|
||||
# s.b. preempt
|
||||
[Pp]re[- ]empt\b
|
||||
|
||||
# s.b. preemptively
|
||||
[Pp]re-emptively
|
||||
[Pp]re[- ]emptively
|
||||
|
||||
# s.b. reentrancy
|
||||
[Rr]e[- ]entrancy
|
||||
|
||||
# s.b. reentrant
|
||||
[Rr]e[- ]entrant
|
||||
|
||||
# s.b. workaround(s)
|
||||
#\bwork[- ]arounds?\b
|
||||
|
||||
# Reject duplicate words
|
||||
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s
|
||||
|
||||
57
.github/actions/spelling/patterns/patterns.txt
vendored
57
.github/actions/spelling/patterns/patterns.txt
vendored
@@ -27,13 +27,68 @@ ROY\sG\.\sBIV
|
||||
# Python stringprefix / binaryprefix
|
||||
\b(?:B|BR|Br|F|FR|Fr|R|RB|RF|Rb|Rf|U|UR|Ur|b|bR|br|f|fR|fr|r|rB|rF|rb|rf|u|uR|ur)'
|
||||
|
||||
# Automatically suggested patterns
|
||||
# hit-count: 3831 file-count: 582
|
||||
# IServiceProvider
|
||||
\bI(?=(?:[A-Z][a-z]{2,})+\b)
|
||||
|
||||
# hit-count: 71 file-count: 35
|
||||
# Compiler flags
|
||||
(?:^|[\t ,"'`=(])-[D](?=[A-Z]{2,}|[A-Z][a-z])
|
||||
(?:^|[\t ,"'`=(])-[X](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
|
||||
|
||||
# hit-count: 41 file-count: 28
|
||||
# version suffix <word>v#
|
||||
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
|
||||
|
||||
# hit-count: 20 file-count: 9
|
||||
# hex runs
|
||||
\b[0-9a-fA-F]{16,}\b
|
||||
|
||||
# hit-count: 10 file-count: 7
|
||||
# uuid:
|
||||
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
|
||||
|
||||
# hit-count: 4 file-count: 4
|
||||
# mailto urls
|
||||
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
|
||||
|
||||
# hit-count: 4 file-count: 1
|
||||
# ANSI color codes
|
||||
(?:\\(?:u00|x)1b|\x1b)\[\d+(?:;\d+|)m
|
||||
|
||||
# hit-count: 2 file-count: 1
|
||||
# latex
|
||||
\\(?:n(?:ew|ormal|osub)|r(?:enew)|t(?:able(?:of|)|he|itle))(?=[a-z]+)
|
||||
|
||||
# hit-count: 1 file-count: 1
|
||||
# hex digits including css/html color classes:
|
||||
(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|u\d+)\b
|
||||
|
||||
# hit-count: 1 file-count: 1
|
||||
# Non-English
|
||||
[a-zA-Z]*[ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*
|
||||
|
||||
# hit-count: 1 file-count: 1
|
||||
# French
|
||||
# This corpus only had capital letters, but you probably want lowercase ones as well.
|
||||
\b[LN]'+[a-z]{2,}\b
|
||||
|
||||
# acceptable duplicates
|
||||
# ls directory listings
|
||||
[-bcdlpsw](?:[-r][-w][-sx]){3}\s+\d+\s+(\S+)\s+\g{-1}\s+\d+\s+
|
||||
# C/idl types + English ...
|
||||
\s(Guid|long|LONG|that) \g{-1}\s
|
||||
|
||||
# javadoc / .net
|
||||
(?:\@(?:groupname|param)|(?:public|private)(?:\s+static|\s+readonly)*)\s+(\w+)\s+\g{-1}\s
|
||||
(?:[\\@](?:groupname|param)|(?:public|private)(?:\s+static|\s+readonly)*)\s+(\w+)\s+\g{-1}\s
|
||||
|
||||
# Commit message -- Signed-off-by and friends
|
||||
^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$
|
||||
|
||||
# Autogenerated revert commit message
|
||||
^This reverts commit [0-9a-f]{40}\.$
|
||||
|
||||
# vtmode
|
||||
--vtmode\s+(\w+)\s+\g{-1}\s
|
||||
|
||||
|
||||
27
.github/actions/spelling/reject.txt
vendored
27
.github/actions/spelling/reject.txt
vendored
@@ -1,31 +1,12 @@
|
||||
benefitting
|
||||
occurences?
|
||||
Sorce
|
||||
^attache$
|
||||
^attacher$
|
||||
^attachers$
|
||||
benefitting
|
||||
occurences?
|
||||
^dependan.*
|
||||
^oer$
|
||||
^spae$
|
||||
^spae-man$
|
||||
^spaebook$
|
||||
^spaecraft$
|
||||
^spaed$
|
||||
^spaedom$
|
||||
^spaeing$
|
||||
^spaeings$
|
||||
^spaeman$
|
||||
^spaer$
|
||||
^Spaerobee$
|
||||
^spaes$
|
||||
^spaewife$
|
||||
^spaewoman$
|
||||
^spaework$
|
||||
^spaewright$
|
||||
Sorce
|
||||
^[Ss]pae.*
|
||||
^untill$
|
||||
^untilling$
|
||||
^wether$
|
||||
^wether.*
|
||||
^wethers$
|
||||
^wetherteg$
|
||||
^[Ss]pae.*
|
||||
|
||||
106
.github/workflows/spelling2.yml
vendored
106
.github/workflows/spelling2.yml
vendored
@@ -1,10 +1,57 @@
|
||||
# spelling.yml is blocked per https://github.com/check-spelling/check-spelling/security/advisories/GHSA-g86g-chm8-7r2p
|
||||
name: Spell checking
|
||||
|
||||
# Comment management is handled through a secondary job, for details see:
|
||||
# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions
|
||||
#
|
||||
# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment
|
||||
# (in odd cases, it might actually run just to collapse a commment, but that's fairly rare)
|
||||
# it needs `contents: write` in order to add a comment.
|
||||
#
|
||||
# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment
|
||||
# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment)
|
||||
# it needs `pull-requests: write` in order to manipulate those comments.
|
||||
|
||||
# Updating pull request branches is managed via comment handling.
|
||||
# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list
|
||||
#
|
||||
# These elements work together to make it happen:
|
||||
#
|
||||
# `on.issue_comment`
|
||||
# This event listens to comments by users asking to update the metadata.
|
||||
#
|
||||
# `jobs.update`
|
||||
# This job runs in response to an issue_comment and will push a new commit
|
||||
# to update the spelling metadata.
|
||||
#
|
||||
# `with.experimental_apply_changes_via_bot`
|
||||
# Tells the action to support and generate messages that enable it
|
||||
# to make a commit to update the spelling metadata.
|
||||
#
|
||||
# `with.ssh_key`
|
||||
# In order to trigger workflows when the commit is made, you can provide a
|
||||
# secret (typically, a write-enabled github deploy key).
|
||||
#
|
||||
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
push:
|
||||
branches: ["**"]
|
||||
tags-ignore: ["**"]
|
||||
branches:
|
||||
- "**"
|
||||
tags-ignore:
|
||||
- "**"
|
||||
pull_request_target:
|
||||
branches:
|
||||
- "**"
|
||||
tags-ignore:
|
||||
- "**"
|
||||
types:
|
||||
- 'opened'
|
||||
- 'reopened'
|
||||
- 'synchronize'
|
||||
issue_comment:
|
||||
types:
|
||||
- 'created'
|
||||
|
||||
jobs:
|
||||
spelling:
|
||||
@@ -24,23 +71,64 @@ jobs:
|
||||
steps:
|
||||
- name: check-spelling
|
||||
id: spelling
|
||||
uses: check-spelling/check-spelling@v0.0.20
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
with:
|
||||
suppress_push_for_open_pull_request: 1
|
||||
checkout: true
|
||||
check_file_names: 1
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
post_comment: 0
|
||||
use_magic_file: 1
|
||||
extra_dictionary_limit: 10
|
||||
extra_dictionaries:
|
||||
cspell:software-terms/src/software-terms.txt
|
||||
cspell:python/src/python/python-lib.txt
|
||||
cspell:node/node.txt
|
||||
cspell:cpp/src/stdlib-c.txt
|
||||
cspell:cpp/src/stdlib-cpp.txt
|
||||
cspell:fullstack/fullstack.txt
|
||||
cspell:filetypes/filetypes.txt
|
||||
cspell:html/html.txt
|
||||
cspell:cpp/src/compiler-msvc.txt
|
||||
cspell:python/src/common/extra.txt
|
||||
cspell:powershell/powershell.txt
|
||||
cspell:aws/aws.txt
|
||||
cspell:cpp/src/lang-keywords.txt
|
||||
cspell:npm/npm.txt
|
||||
cspell:dotnet/dotnet.txt
|
||||
cspell:python/src/python/python.txt
|
||||
cspell:css/css.txt
|
||||
cspell:cpp/src/stdlib-cmath.txt
|
||||
check_extra_dictionaries: ''
|
||||
|
||||
comment:
|
||||
name: Report
|
||||
comment-push:
|
||||
name: Report (Push)
|
||||
# If your workflow isn't running on push, you can remove this job
|
||||
runs-on: ubuntu-latest
|
||||
needs: spelling
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name != 'push'
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.20
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
with:
|
||||
checkout: true
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
task: ${{ needs.spelling.outputs.followup }}
|
||||
|
||||
comment-pr:
|
||||
name: Report (PR)
|
||||
# If you workflow isn't running on pull_request*, you can remove this job
|
||||
runs-on: ubuntu-latest
|
||||
needs: spelling
|
||||
permissions:
|
||||
pull-requests: write
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@v0.0.21
|
||||
with:
|
||||
checkout: true
|
||||
spell_check_this: check-spelling/spell-check-this@prerelease
|
||||
task: ${{ needs.spelling.outputs.followup }}
|
||||
|
||||
@@ -2396,7 +2396,10 @@
|
||||
},
|
||||
"startingDirectory": {
|
||||
"description": "The directory the shell starts in when it is loaded.",
|
||||
"type": "string"
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"suppressApplicationTitle": {
|
||||
"description": "When set to true, tabTitle overrides the default title of the tab and any title change messages from the application will be suppressed. When set to false, tabTitle behaves as normal.",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
author: Mike Griese @zadjii-msft
|
||||
created on: 2020-5-13
|
||||
last updated: 2020-08-04
|
||||
last updated: 2022-11-18
|
||||
issue id: 1571
|
||||
---
|
||||
|
||||
@@ -76,6 +76,34 @@ There are five `type`s of objects in this menu:
|
||||
- The `"entries"` property specifies a list of menu entries that will appear
|
||||
nested under this entry. This can contain other `"type":"folder"` groups as
|
||||
well!
|
||||
- The `"inline"` property accepts two values
|
||||
- `auto`: When the folder only has one entry in it, don't actually create a
|
||||
nested layer to then menu. Just place the single entry in the layer that
|
||||
folder would occupy. (Useful for dynamic profile sources with only a
|
||||
single entry).
|
||||
- `never`: (**default**) Always create a nested entry, even for a single
|
||||
sub-item.
|
||||
- The `allowEmpty` property will force this entry to show up in the menu, even
|
||||
if it doesn't have any profiles in it. This defaults to `false`, meaning
|
||||
that folders without any entries in them will just be ignored when
|
||||
generating the menu. This will be more useful with the `matchProfile` entry,
|
||||
below.
|
||||
|
||||
When this is true, and the folder is empty, we should add a
|
||||
placeholder `<empty>` entry to the menu, to indicate that no profiles were
|
||||
in that folder.
|
||||
- _This setting is probably pretty niche, and not a requirement_. More of a
|
||||
theoretical suggestion than anything.
|
||||
- In the case of no entries for this folder, we should make sure to also
|
||||
reflect the `inline` property:
|
||||
- `allowEmpty:true`, `inline:auto`: just ignore the entry at all. Don't
|
||||
add a placeholder to the parent list.
|
||||
- `allowEmpty:true`, `inline:never`: Add a nested entry, with an
|
||||
`<empty>` placeholder.
|
||||
- `allowEmpty:false`, `inline:auto`: just ignore the entry at all. Don't
|
||||
add a placeholder to the parent list.
|
||||
- `allowEmpty:false`, `inline:never`: just ignore the entry at all. Don't
|
||||
add a placeholder to the parent list.
|
||||
* `"type":"action"`: This represents a menu entry that should execute a specific
|
||||
`ShortcutAction`.
|
||||
- the `id` property will specify the global action ID (see [#6899], [#7175])
|
||||
@@ -97,6 +125,16 @@ There are five `type`s of objects in this menu:
|
||||
enabling all other profiles to also be accessible.
|
||||
- The "name" of these entries will simply be the name of the profile
|
||||
- The "icon" of these entries will simply be the profile's icon
|
||||
- This won't include any profiles that have been included via `matchProfile`
|
||||
entries (below)
|
||||
* `"type": "matchProfile"`: Expands to all the profiles that match a given
|
||||
string. This lets the user easily specify a whole collection of profiles for a
|
||||
folder, without needing to add them all manually.
|
||||
- `"name"`, `"commandline"` or `"source"`: These three properties are used to
|
||||
filter the list of profiles, based on the matching property in the profile
|
||||
itself. The value is a string to compare with the corresponding property in
|
||||
the profile. A full string comparison is done - not a regex or partial
|
||||
string match.
|
||||
|
||||
The "default" new tab menu could be imagined as the following blob of json:
|
||||
|
||||
@@ -108,6 +146,42 @@ The "default" new tab menu could be imagined as the following blob of json:
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, we could consider something like the following. This would place
|
||||
CMD, PowerShell, and all PowerShell cores in the root at the top, followed by
|
||||
nested entries for each subsequent dynamic profile generator.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"newTabMenu": [
|
||||
{ "type":"profile", "profile": "cmd" },
|
||||
{ "type":"profile", "profile": "Windows PowerShell" },
|
||||
{ "type": "matchProfile", "source": "Microsoft.Terminal.PowerShellCore" }
|
||||
{
|
||||
"type": "folder",
|
||||
"name": "WSL",
|
||||
"entries": [ { "type": "matchProfile", "source": "Microsoft.Terminal.Wsl" } ]
|
||||
},
|
||||
{
|
||||
"type": "folder",
|
||||
"name": "Visual Studio",
|
||||
"entries": [ { "type": "matchProfile", "source": "Microsoft.Terminal.VisualStudio" } ]
|
||||
},
|
||||
// ... etc for other profile generators
|
||||
{ "type": "remainingProfiles" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
I might only recommend that for `userDefaults.json`, which is the json files
|
||||
used as a template for a user's new settings file. This would prevent us from
|
||||
moving the user's cheese too much, if they're already using the Terminal and
|
||||
happy with their list as is. Especially consider someone who's default profile
|
||||
is a WSL distro, which would now need two clicks to get to.
|
||||
|
||||
> _note_: We will also want to support the same `{ "key": "SomeResourceString"}`
|
||||
> syntax used by the Command Palette commands
|
||||
> for specifying localizable names, if we chose to pursue this route.
|
||||
|
||||
### Other considerations
|
||||
|
||||
Also considered during the investigation for this feature was re-using the list
|
||||
@@ -154,6 +228,42 @@ The design chosen in this spec more cleanly separates the responsibilities of
|
||||
the list of profiles and the contents of the new tab menu. This way, each object
|
||||
can be defined independent of the structure of the other.
|
||||
|
||||
Regarding implementation of `matchProfile` entries: In order to build the menu,
|
||||
we'll evaluate the entries in the following order:
|
||||
|
||||
* all explicit `profile` entries
|
||||
* then all `matchProfile` entries, using profiles not already specified
|
||||
* then expand out `remainingProfiles` with anything not found above.
|
||||
|
||||
As an example:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"newTabMenu": [
|
||||
{ "type": "matchProfile", "source": "Microsoft.Terminal.Wsl" }
|
||||
{
|
||||
"type": "folder",
|
||||
"name": "WSLs",
|
||||
"entries": [ { "type": "matchProfile", "source": "Microsoft.Terminal.Wsl" } ]
|
||||
},
|
||||
{ "type": "remainingProfiles" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
For profiles { "Profile A", "Profile B (WSL)", "Profile C (WSL)" }, This would
|
||||
expand to:
|
||||
|
||||
```
|
||||
New Tab Button ▽
|
||||
├─ Profile A
|
||||
├─ Profile B (WSL)
|
||||
├─ Profile C (WSL)
|
||||
└─ WSLs
|
||||
└─ Profile B (WSL)
|
||||
└─ Profile C (WSL)
|
||||
```
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
See the above _figure 1_.
|
||||
@@ -289,7 +399,39 @@ And assuming the user has bound:
|
||||
- Close Tab: `{ "action": "closeTab", "index": "${selectedTab.index}" }`
|
||||
- Close Other Tabs: `{ "action": "closeTabs", "otherThan": "${selectedTab.index}" }`
|
||||
- Close Tabs to the Right: `{ "action": "closeTabs", "after": "${selectedTab.index}" }`
|
||||
* We may want to consider regex, tag-based, or some other type of matching for
|
||||
`matchProfile` entries in the future. We originally considered using regex for
|
||||
`matchProfile` by default, but decided instead on full string matches to leave
|
||||
room for regex matching in the future. Should we chose to pursue something
|
||||
like that, we should use a settings structure like:
|
||||
|
||||
```json
|
||||
"type": "profileMatch",
|
||||
"source": { "type": "regex", "value": ".*wsl.*" }
|
||||
```
|
||||
* We may want to expand `matchProfile` to match on other properties too. (`title`?)
|
||||
* We may want to consider adding support for capture groups, e.g.
|
||||
```json
|
||||
{
|
||||
"type": "profileMatch",
|
||||
"name": { "type": "regex", "value": "^ssh: (.*)" }
|
||||
}
|
||||
```
|
||||
for matching to all your `ssh: ` profiles, but populate the name in the entry
|
||||
with that first capture group. So, ["ssh: foo", "ssh: bar"] would just expand
|
||||
to a "foo" and "bar" entry.
|
||||
|
||||
## Updates
|
||||
|
||||
_February 2022_: Doc updated in response to some discussion in [#11326] and
|
||||
[#7774]. In those PRs, it became clear that there needs to be a simple way of
|
||||
collecting up a whole group of profiles automatically for sorting in these
|
||||
menus. Although discussion centered on how hard it would be for extensions to
|
||||
provide that customization themselves, the `match` statement was added as a way
|
||||
to allow the user to easily filter those profiles themselves.
|
||||
|
||||
This was something we had originally considered as a "future consideration", but
|
||||
ultimately deemed it to be out of scope for the initial spec review.
|
||||
|
||||
<!-- Footnotes -->
|
||||
[#2046]: https://github.com/microsoft/terminal/issues/2046
|
||||
@@ -298,3 +440,5 @@ And assuming the user has bound:
|
||||
[#3337]: https://github.com/microsoft/terminal/issues/3337
|
||||
[#6899]: https://github.com/microsoft/terminal/issues/6899
|
||||
[#7175]: https://github.com/microsoft/terminal/issues/7175
|
||||
[#11326]: https://github.com/microsoft/terminal/issues/11326
|
||||
[#7774]: https://github.com/microsoft/terminal/issues/7774
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
#include "OutputCellIterator.hpp"
|
||||
|
||||
#include <til/unicode.h>
|
||||
|
||||
#include "../../types/inc/convert.hpp"
|
||||
#include "../../types/inc/Utf16Parser.hpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
#include "../../inc/conattrs.hpp"
|
||||
|
||||
@@ -392,7 +393,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view,
|
||||
const TextAttribute attr,
|
||||
const TextAttributeBehavior behavior)
|
||||
{
|
||||
const auto glyph = Utf16Parser::ParseNext(view);
|
||||
const auto glyph = til::utf16_next(view);
|
||||
const auto dbcsAttr = IsGlyphFullWidth(glyph) ? DbcsAttribute::Leading : DbcsAttribute::Single;
|
||||
return OutputCellView(glyph, dbcsAttr, attr, behavior);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
#include "search.h"
|
||||
|
||||
#include <til/unicode.h>
|
||||
|
||||
#include "textBuffer.hpp"
|
||||
#include "../types/inc/Utf16Parser.hpp"
|
||||
#include "../types/inc/GlyphWidth.hpp"
|
||||
|
||||
using namespace Microsoft::Console::Types;
|
||||
@@ -192,12 +193,11 @@ bool Search::_FindNeedleInHaystackAt(const til::point pos, til::point& start, ti
|
||||
|
||||
auto bufferPos = pos;
|
||||
|
||||
for (const auto& needleCell : _needle)
|
||||
for (const auto& needleChars : _needle)
|
||||
{
|
||||
// Haystack is the buffer. Needle is the string we were given.
|
||||
const auto hayIter = _uiaData.GetTextBuffer().GetTextDataAt(bufferPos);
|
||||
const auto hayChars = *hayIter;
|
||||
const auto needleChars = std::wstring_view(needleCell.data(), needleCell.size());
|
||||
|
||||
// If we didn't match at any point of the needle, return false.
|
||||
if (!_CompareChars(hayChars, needleChars))
|
||||
@@ -328,13 +328,12 @@ void Search::_UpdateNextPosition()
|
||||
// - wstr - String that will be our search term
|
||||
// Return Value:
|
||||
// - Structured text data for comparison to screen buffer text data.
|
||||
std::vector<std::vector<wchar_t>> Search::s_CreateNeedleFromString(const std::wstring_view wstr)
|
||||
std::vector<std::wstring> Search::s_CreateNeedleFromString(const std::wstring_view wstr)
|
||||
{
|
||||
const auto charData = Utf16Parser::Parse(wstr);
|
||||
std::vector<std::vector<wchar_t>> cells;
|
||||
for (const auto chars : charData)
|
||||
std::vector<std::wstring> cells;
|
||||
for (const auto& chars : til::utf16_iterator{ wstr })
|
||||
{
|
||||
if (IsGlyphFullWidth(std::wstring_view{ chars.data(), chars.size() }))
|
||||
if (IsGlyphFullWidth(chars))
|
||||
{
|
||||
cells.emplace_back(chars);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
|
||||
static til::point s_GetInitialAnchor(const Microsoft::Console::Types::IUiaData& uiaData, const Direction dir);
|
||||
|
||||
static std::vector<std::vector<wchar_t>> s_CreateNeedleFromString(const std::wstring_view wstr);
|
||||
static std::vector<std::wstring> s_CreateNeedleFromString(const std::wstring_view wstr);
|
||||
|
||||
bool _reachedEnd = false;
|
||||
til::point _coordNext;
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
til::point _coordSelEnd;
|
||||
|
||||
const til::point _coordAnchor;
|
||||
const std::vector<std::vector<wchar_t>> _needle;
|
||||
const std::vector<std::wstring> _needle;
|
||||
const Direction _direction;
|
||||
const Sensitivity _sensitivity;
|
||||
Microsoft::Console::Types::IUiaData& _uiaData;
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
#include "textBuffer.hpp"
|
||||
|
||||
#include <til/hash.h>
|
||||
#include <til/unicode.h>
|
||||
|
||||
#include "../renderer/base/renderer.hpp"
|
||||
#include "../types/inc/utils.hpp"
|
||||
#include "../types/inc/convert.hpp"
|
||||
#include "../../types/inc/Utf16Parser.hpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
namespace
|
||||
@@ -2810,16 +2810,14 @@ PointTree TextBuffer::GetPatterns(const til::CoordType firstRow, const til::Coor
|
||||
// match and the previous match, so we use the size of the prefix
|
||||
// along with the size of the match to determine the locations
|
||||
til::CoordType prefixSize = 0;
|
||||
for (const auto parsedGlyph : Utf16Parser::Parse(i->prefix().str()))
|
||||
for (const auto str = i->prefix().str(); const auto& glyph : til::utf16_iterator{ str })
|
||||
{
|
||||
const std::wstring_view glyph{ parsedGlyph.data(), parsedGlyph.size() };
|
||||
prefixSize += IsGlyphFullWidth(glyph) ? 2 : 1;
|
||||
}
|
||||
const auto start = lenUpToThis + prefixSize;
|
||||
til::CoordType matchSize = 0;
|
||||
for (const auto parsedGlyph : Utf16Parser::Parse(i->str()))
|
||||
for (const auto str = i->str(); const auto& glyph : til::utf16_iterator{ str })
|
||||
{
|
||||
const std::wstring_view glyph{ parsedGlyph.data(), parsedGlyph.size() };
|
||||
matchSize += IsGlyphFullWidth(glyph) ? 2 : 1;
|
||||
}
|
||||
const auto end = start + matchSize;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include "../textBuffer.hpp"
|
||||
#include "../../renderer/inc/DummyRenderer.hpp"
|
||||
#include "../../types/inc/Utf16Parser.hpp"
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
#include <IDataSource.h>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include <DefaultSettings.h>
|
||||
#include <unicode.hpp>
|
||||
#include <Utf16Parser.hpp>
|
||||
#include <WinUser.h>
|
||||
#include <LibraryResources.h>
|
||||
|
||||
@@ -1744,7 +1743,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto strEnd = rowText.find_last_not_of(UNICODE_SPACE);
|
||||
if (strEnd != decltype(rowText)::npos)
|
||||
{
|
||||
str.append(rowText.substr(strEnd + 1));
|
||||
str.append(rowText.substr(0, strEnd + 1));
|
||||
}
|
||||
|
||||
if (!row.WasWrapForced())
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "ControlInteractivity.h"
|
||||
#include <DefaultSettings.h>
|
||||
#include <unicode.hpp>
|
||||
#include <Utf16Parser.hpp>
|
||||
#include <Utils.h>
|
||||
#include <LibraryResources.h>
|
||||
#include "../../types/inc/GlyphWidth.hpp"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "TermControl.h"
|
||||
|
||||
#include <unicode.hpp>
|
||||
#include <Utf16Parser.hpp>
|
||||
#include <LibraryResources.h>
|
||||
|
||||
#include "TermControlAutomationPeer.h"
|
||||
|
||||
@@ -88,6 +88,11 @@
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.DetectURLs, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<local:SettingContainer x:Uid="Globals_ConfirmCloseAllTabs">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ConfirmCloseAllTabs, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Page>
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, FocusFollowMouse);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, DetectURLs);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, WordDelimiters);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_GlobalSettings, ConfirmCloseAllTabs);
|
||||
|
||||
private:
|
||||
Model::GlobalAppSettings _GlobalSettings;
|
||||
|
||||
@@ -24,5 +24,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, FocusFollowMouse);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, DetectURLs);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(String, WordDelimiters);
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(Boolean, ConfirmCloseAllTabs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1557,4 +1557,8 @@
|
||||
<value>Set as default</value>
|
||||
<comment>Text label for a button that, when invoked, sets the selected color scheme as the default scheme to use.</comment>
|
||||
</data>
|
||||
<data name="Globals_ConfirmCloseAllTabs.Header" xml:space="preserve">
|
||||
<value>Confirm before closing all tabs</value>
|
||||
<comment>Header for a control to toggle whether to show a confirm dialog box when closing the application with multiple tabs open.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "DefaultTerminal.h"
|
||||
#include "FileUtils.h"
|
||||
|
||||
using namespace winrt::Windows::Storage;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Windows::ApplicationModel::AppExtensions;
|
||||
using namespace winrt::Microsoft::Terminal::Settings;
|
||||
@@ -912,6 +913,65 @@ try
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
|
||||
}
|
||||
|
||||
const auto _ = [&]() -> winrt::fire_and_forget {
|
||||
co_await winrt::resume_background();
|
||||
co_await winrt::resume_after(std::chrono::seconds(2));
|
||||
|
||||
{
|
||||
const auto folder = winrt::Windows::Storage::ApplicationData::Current().LocalFolder();
|
||||
auto file = co_await folder.GetFileAsync(SettingsFilename);
|
||||
auto props = co_await file.GetBasicPropertiesAsync();
|
||||
|
||||
const auto beg = std::chrono::high_resolution_clock::now();
|
||||
for (size_t i = 0; i < 1000; ++i)
|
||||
{
|
||||
file = co_await folder.GetFileAsync(SettingsFilename);
|
||||
props = co_await file.GetBasicPropertiesAsync();
|
||||
}
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
const auto dur = std::chrono::duration<double>(end - beg).count();
|
||||
|
||||
auto out = std::to_wstring(dur);
|
||||
out += L"ms\n";
|
||||
OutputDebugStringW(out.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
const auto path = _settingsPath();
|
||||
|
||||
FILETIME ftCreate, ftAccess, ftWrite;
|
||||
wil::unique_hfile file{ CreateFileW(path.c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr) };
|
||||
THROW_LAST_ERROR_IF(!file);
|
||||
THROW_LAST_ERROR_IF(!GetFileTime(file.get(), &ftCreate, &ftAccess, &ftWrite));
|
||||
|
||||
const auto beg = std::chrono::high_resolution_clock::now();
|
||||
for (size_t i = 0; i < 1000; ++i)
|
||||
{
|
||||
file = wil::unique_hfile{ CreateFileW(path.c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr) };
|
||||
THROW_LAST_ERROR_IF(!file);
|
||||
THROW_LAST_ERROR_IF(!GetFileTime(file.get(), &ftCreate, &ftAccess, &ftWrite));
|
||||
}
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
const auto dur = std::chrono::duration<double>(end - beg).count();
|
||||
|
||||
auto out = std::to_wstring(dur);
|
||||
out += L"ms\n";
|
||||
OutputDebugStringW(out.c_str());
|
||||
}
|
||||
}();
|
||||
|
||||
return *settings;
|
||||
}
|
||||
catch (const SettingsException& ex)
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace ControlUnitTests
|
||||
TEST_METHOD(TestClearScrollback);
|
||||
TEST_METHOD(TestClearScreen);
|
||||
TEST_METHOD(TestClearAll);
|
||||
TEST_METHOD(TestReadEntireBuffer);
|
||||
|
||||
TEST_CLASS_SETUP(ModuleSetup)
|
||||
{
|
||||
@@ -340,4 +341,22 @@ namespace ControlUnitTests
|
||||
// The ConptyRoundtripTests test the actual clearing of the contents.
|
||||
}
|
||||
|
||||
void ControlCoreTests::TestReadEntireBuffer()
|
||||
{
|
||||
auto [settings, conn] = _createSettingsAndConnection();
|
||||
Log::Comment(L"Create ControlCore object");
|
||||
auto core = createCore(*settings, *conn);
|
||||
VERIFY_IS_NOT_NULL(core);
|
||||
_standardInit(core);
|
||||
|
||||
Log::Comment(L"Print some text");
|
||||
conn->WriteInput(L"This is some text \r\n");
|
||||
conn->WriteInput(L"with varying amounts \r\n");
|
||||
conn->WriteInput(L"of whitespace \r\n");
|
||||
|
||||
Log::Comment(L"Check the buffer contents");
|
||||
VERIFY_ARE_EQUAL(L"This is some text\r\nwith varying amounts\r\nof whitespace\r\n",
|
||||
core->ReadEntireBuffer());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||
#include "../types/inc/Viewport.hpp"
|
||||
#include "../types/inc/convert.hpp"
|
||||
#include "../types/inc/Utf16Parser.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include "conimeinfo.h"
|
||||
#include "conareainfo.h"
|
||||
|
||||
#include <til/unicode.h>
|
||||
|
||||
#include "conareainfo.h"
|
||||
#include "_output.h"
|
||||
#include "dbcs.h"
|
||||
|
||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||
#include "../types/inc/GlyphWidth.hpp"
|
||||
#include "../types/inc/Utf16Parser.hpp"
|
||||
|
||||
// Attributes flags:
|
||||
#define COMMON_LVB_GRID_SINGLEFLAG 0x2000 // DBCS: Grid attribute: use for ime cursor.
|
||||
@@ -223,12 +223,9 @@ std::vector<OutputCell> ConsoleImeInfo::s_ConvertToCells(const std::wstring_view
|
||||
{
|
||||
std::vector<OutputCell> cells;
|
||||
|
||||
// - Convert incoming wchar_t stream into UTF-16 units.
|
||||
const auto glyphs = Utf16Parser::Parse(text);
|
||||
|
||||
// - Walk through all of the grouped up text, match up the correct attribute to it, and make a new cell.
|
||||
size_t attributesUsed = 0;
|
||||
for (const auto& parsedGlyph : glyphs)
|
||||
for (const auto& parsedGlyph : til::utf16_iterator{ text })
|
||||
{
|
||||
const std::wstring_view glyph{ parsedGlyph.data(), parsedGlyph.size() };
|
||||
// Collect up attributes that apply to this glyph range.
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
<ClCompile Include="TitleTests.cpp" />
|
||||
<ClCompile Include="UtilsTests.cpp" />
|
||||
<ClCompile Include="Utf8ToWideCharParserTests.cpp" />
|
||||
<ClCompile Include="Utf16ParserTests.cpp" />
|
||||
<ClCompile Include="InputBufferTests.cpp" />
|
||||
<ClCompile Include="ReadWaitTests.cpp" />
|
||||
<ClCompile Include="ViewportTests.cpp" />
|
||||
|
||||
@@ -72,9 +72,6 @@
|
||||
<ClCompile Include="AliasTests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Utf16ParserTests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SearchTests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "WexTestClass.h"
|
||||
#include "../../inc/consoletaeftemplates.hpp"
|
||||
|
||||
#include "../../types/inc/Utf16Parser.hpp"
|
||||
|
||||
using namespace WEX::Common;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
|
||||
static const std::vector<wchar_t> CyrillicChar = { 0x0431 }; // lowercase be
|
||||
static const std::vector<wchar_t> LatinChar = { 0x0061 }; // uppercase A
|
||||
static const std::vector<wchar_t> FullWidthChar = { 0xFF2D }; // fullwidth latin small letter m
|
||||
static const std::vector<wchar_t> GaelicChar = { 0x1E41 }; // latin small letter m with dot above
|
||||
static const std::vector<wchar_t> HiraganaChar = { 0x3059 }; // hiragana su
|
||||
static const std::vector<wchar_t> SunglassesEmoji = { 0xD83D, 0xDE0E }; // smiling face with sunglasses emoji
|
||||
|
||||
class Utf16ParserTests
|
||||
{
|
||||
TEST_CLASS(Utf16ParserTests);
|
||||
|
||||
TEST_METHOD(CanParseNonSurrogateText)
|
||||
{
|
||||
const std::vector<std::vector<wchar_t>> expected = { CyrillicChar, LatinChar, FullWidthChar, GaelicChar, HiraganaChar };
|
||||
|
||||
std::wstring wstr;
|
||||
for (const auto& charData : expected)
|
||||
{
|
||||
wstr.push_back(charData.at(0));
|
||||
}
|
||||
|
||||
const auto result = Utf16Parser::Parse(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected.size(), result.size());
|
||||
for (size_t i = 0; i < result.size(); ++i)
|
||||
{
|
||||
const auto& sequence = result.at(i);
|
||||
VERIFY_ARE_EQUAL(sequence, expected.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(CanParseSurrogatePairs)
|
||||
{
|
||||
const std::wstring wstr{ SunglassesEmoji.begin(), SunglassesEmoji.end() };
|
||||
const auto result = Utf16Parser::Parse(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(result.size(), 1u);
|
||||
VERIFY_ARE_EQUAL(result.at(0).size(), SunglassesEmoji.size());
|
||||
for (size_t i = 0; i < SunglassesEmoji.size(); ++i)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(result.at(0).at(i), SunglassesEmoji.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(WillDropBadSurrogateCombinations)
|
||||
{
|
||||
// test dropping of invalid leading surrogates
|
||||
std::wstring wstr{ SunglassesEmoji.begin(), SunglassesEmoji.end() };
|
||||
wstr += wstr;
|
||||
wstr.at(1) = SunglassesEmoji.at(0); // wstr contains 3 leading, 1 trailing surrogate sequence
|
||||
|
||||
auto result = Utf16Parser::Parse(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(result.size(), 1u);
|
||||
VERIFY_ARE_EQUAL(result.at(0).size(), SunglassesEmoji.size());
|
||||
for (size_t i = 0; i < SunglassesEmoji.size(); ++i)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(result.at(0).at(i), SunglassesEmoji.at(i));
|
||||
}
|
||||
|
||||
// test dropping of invalid trailing surrogates
|
||||
wstr = { SunglassesEmoji.begin(), SunglassesEmoji.end() };
|
||||
wstr += wstr;
|
||||
wstr.at(0) = SunglassesEmoji.at(1); // wstr contains 2 trailing, 1 leading, 1 trailing surrogate sequence
|
||||
|
||||
result = Utf16Parser::Parse(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(result.size(), 1u);
|
||||
VERIFY_ARE_EQUAL(result.at(0).size(), SunglassesEmoji.size());
|
||||
for (size_t i = 0; i < SunglassesEmoji.size(); ++i)
|
||||
{
|
||||
VERIFY_ARE_EQUAL(result.at(0).at(i), SunglassesEmoji.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
const std::wstring_view Replacement{ &UNICODE_REPLACEMENT, 1 };
|
||||
|
||||
TEST_METHOD(ParseNextLeadOnly)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(0) };
|
||||
|
||||
const auto expected = Replacement;
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextTrailOnly)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(1) };
|
||||
|
||||
const auto expected = Replacement;
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextSingleOnly)
|
||||
{
|
||||
std::wstring wstr{ CyrillicChar.at(0) };
|
||||
|
||||
const auto expected = std::wstring_view{ CyrillicChar.data(), CyrillicChar.size() };
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextLeadLead)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(0) };
|
||||
wstr += SunglassesEmoji.at(0);
|
||||
|
||||
const auto expected = Replacement;
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextLeadTrail)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(0) };
|
||||
wstr += SunglassesEmoji.at(1);
|
||||
|
||||
const auto expected = std::wstring_view{ SunglassesEmoji.data(), SunglassesEmoji.size() };
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextTrailTrail)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(1) };
|
||||
wstr += SunglassesEmoji.at(1);
|
||||
|
||||
const auto expected = Replacement;
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextLeadSingle)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(0) };
|
||||
wstr += LatinChar.at(0);
|
||||
|
||||
const auto expected = std::wstring_view{ LatinChar.data(), LatinChar.size() };
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextTrailSingle)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(1) };
|
||||
wstr += LatinChar.at(0);
|
||||
|
||||
const auto expected = std::wstring_view{ LatinChar.data(), LatinChar.size() };
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextLeadLeadTrail)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(0) };
|
||||
wstr += SunglassesEmoji.at(0);
|
||||
wstr += SunglassesEmoji.at(1);
|
||||
|
||||
const auto expected = std::wstring_view{ SunglassesEmoji.data(), SunglassesEmoji.size() };
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextTrailLeadTrail)
|
||||
{
|
||||
std::wstring wstr{ SunglassesEmoji.at(1) };
|
||||
wstr += SunglassesEmoji.at(0);
|
||||
wstr += SunglassesEmoji.at(1);
|
||||
|
||||
const auto expected = std::wstring_view{ SunglassesEmoji.data(), SunglassesEmoji.size() };
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
TEST_METHOD(ParseNextSingleLeadTrail)
|
||||
{
|
||||
std::wstring wstr{ GaelicChar.at(0) };
|
||||
wstr += SunglassesEmoji.at(0);
|
||||
wstr += SunglassesEmoji.at(1);
|
||||
|
||||
const auto expected = std::wstring_view{ GaelicChar.data(), GaelicChar.size() };
|
||||
const auto actual = Utf16Parser::ParseNext(wstr);
|
||||
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
};
|
||||
@@ -28,7 +28,6 @@ SOURCES = \
|
||||
ClipboardTests.cpp \
|
||||
SelectionTests.cpp \
|
||||
Utf8ToWideCharParserTests.cpp \
|
||||
Utf16ParserTests.cpp \
|
||||
OutputCellIteratorTests.cpp \
|
||||
InitTests.cpp \
|
||||
TitleTests.cpp \
|
||||
|
||||
164
src/inc/til/unicode.h
Normal file
164
src/inc/til/unicode.h
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace til
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
inline constexpr wchar_t UNICODE_REPLACEMENT = 0xFFFD;
|
||||
}
|
||||
|
||||
static constexpr bool is_surrogate(const wchar_t wch) noexcept
|
||||
{
|
||||
return (wch & 0xF800) == 0xD800;
|
||||
}
|
||||
|
||||
static constexpr bool is_leading_surrogate(const wchar_t wch) noexcept
|
||||
{
|
||||
return (wch & 0xFC00) == 0xD800;
|
||||
}
|
||||
|
||||
static constexpr bool is_trailing_surrogate(const wchar_t wch) noexcept
|
||||
{
|
||||
return (wch & 0xFC00) == 0xDC00;
|
||||
}
|
||||
|
||||
// Verifies the beginning of the given UTF16 string and returns the first UTF16 sequence
|
||||
// or U+FFFD otherwise. It's not really useful and at the time of writing only a
|
||||
// single caller uses this. It's best to delete this if you read this comment.
|
||||
constexpr std::wstring_view utf16_next(std::wstring_view wstr) noexcept
|
||||
{
|
||||
auto it = wstr.begin();
|
||||
const auto end = wstr.end();
|
||||
auto ptr = &details::UNICODE_REPLACEMENT;
|
||||
size_t len = 1;
|
||||
|
||||
if (it != end)
|
||||
{
|
||||
const auto wch = *it;
|
||||
ptr = &*it;
|
||||
|
||||
if (is_surrogate(wch))
|
||||
{
|
||||
++it;
|
||||
const auto wch2 = it != end ? *it : wchar_t{};
|
||||
if (is_leading_surrogate(wch) && is_trailing_surrogate(wch2))
|
||||
{
|
||||
len = 2;
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = &details::UNICODE_REPLACEMENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { ptr, len };
|
||||
}
|
||||
|
||||
// Splits a UTF16 string into codepoints, yielding `wstring_view`s of UTF16 text. Use it as:
|
||||
// for (const auto& str : til::utf16_iterator{ input }) { ... }
|
||||
struct utf16_iterator
|
||||
{
|
||||
struct sentinel
|
||||
{
|
||||
};
|
||||
|
||||
struct iterator
|
||||
{
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = std::wstring_view;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
explicit constexpr iterator(utf16_iterator& p) noexcept :
|
||||
_iter{ p }
|
||||
{
|
||||
}
|
||||
|
||||
const value_type& operator*() const noexcept
|
||||
{
|
||||
return _iter.value();
|
||||
}
|
||||
|
||||
iterator& operator++() noexcept
|
||||
{
|
||||
_iter._advance = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const sentinel&) const noexcept
|
||||
{
|
||||
return _iter.valid();
|
||||
}
|
||||
|
||||
private:
|
||||
utf16_iterator& _iter;
|
||||
};
|
||||
|
||||
explicit constexpr utf16_iterator(std::wstring_view wstr) noexcept :
|
||||
_it{ wstr.begin() }, _end{ wstr.end() }, _advance{ _it != _end }
|
||||
{
|
||||
}
|
||||
|
||||
iterator begin() noexcept
|
||||
{
|
||||
return iterator{ *this };
|
||||
}
|
||||
|
||||
sentinel end() noexcept
|
||||
{
|
||||
return sentinel{};
|
||||
}
|
||||
|
||||
private:
|
||||
bool valid() const noexcept
|
||||
{
|
||||
return _it != _end;
|
||||
}
|
||||
|
||||
void advance() noexcept
|
||||
{
|
||||
const auto wch = *_it;
|
||||
auto ptr = &*_it;
|
||||
size_t len = 1;
|
||||
|
||||
++_it;
|
||||
|
||||
if (is_surrogate(wch))
|
||||
{
|
||||
const auto wch2 = _it != _end ? *_it : wchar_t{};
|
||||
if (is_leading_surrogate(wch) && is_trailing_surrogate(wch2))
|
||||
{
|
||||
len = 2;
|
||||
++_it;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = &details::UNICODE_REPLACEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
_value = { ptr, len };
|
||||
_advance = false;
|
||||
}
|
||||
|
||||
const std::wstring_view& value() noexcept
|
||||
{
|
||||
if (_advance)
|
||||
{
|
||||
advance();
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
std::wstring_view::iterator _it;
|
||||
std::wstring_view::iterator _end;
|
||||
std::wstring_view _value;
|
||||
bool _advance = true;
|
||||
};
|
||||
}
|
||||
@@ -2,17 +2,16 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include <windows.h>
|
||||
#include "terminalInput.hpp"
|
||||
|
||||
#include "strsafe.h"
|
||||
#include <til/unicode.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#define WIL_SUPPORT_BITOPERATION_PASCAL_NAMES
|
||||
#include <wil/Common.h>
|
||||
|
||||
#include "../../interactivity/inc/VtApiRedirection.hpp"
|
||||
#include "../../inc/unicode.hpp"
|
||||
#include "../../types/inc/Utf16Parser.hpp"
|
||||
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
||||
@@ -739,7 +738,7 @@ bool TerminalInput::HandleFocus(const bool focused) noexcept
|
||||
// - ch: The UTF-16 character to send.
|
||||
void TerminalInput::_SendChar(const wchar_t ch)
|
||||
{
|
||||
if (Utf16Parser::IsLeadingSurrogate(ch))
|
||||
if (til::is_leading_surrogate(ch))
|
||||
{
|
||||
if (_leadingSurrogate.has_value())
|
||||
{
|
||||
|
||||
82
src/til/ut_til/UnicodeTests.cpp
Normal file
82
src/til/ut_til/UnicodeTests.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "WexTestClass.h"
|
||||
|
||||
#include <til/unicode.h>
|
||||
|
||||
using namespace WEX::Common;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
|
||||
#define REPLACEMENT L"\xFFFD"
|
||||
#define LEADING L"\xD801"
|
||||
#define TRAILING L"\xDC01"
|
||||
#define PAIR L"\xD801\xDC01"
|
||||
|
||||
class UnicodeTests
|
||||
{
|
||||
TEST_CLASS(UnicodeTests);
|
||||
|
||||
TEST_METHOD(utf16_next)
|
||||
{
|
||||
struct Test
|
||||
{
|
||||
std::wstring_view input;
|
||||
std::wstring_view expected;
|
||||
};
|
||||
|
||||
static constexpr std::array tests{
|
||||
Test{ L"", REPLACEMENT },
|
||||
Test{ L"a", L"a" },
|
||||
Test{ L"abc", L"a" },
|
||||
Test{ L"a" PAIR, L"a" },
|
||||
Test{ L"a" LEADING, L"a" },
|
||||
Test{ L"a" TRAILING, L"a" },
|
||||
Test{ PAIR L"a", PAIR },
|
||||
Test{ LEADING L"a", REPLACEMENT },
|
||||
Test{ TRAILING L"a", REPLACEMENT },
|
||||
};
|
||||
|
||||
for (const auto& t : tests)
|
||||
{
|
||||
const auto actual = til::utf16_next(t.input);
|
||||
VERIFY_ARE_EQUAL(t.expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(utf16_iterator)
|
||||
{
|
||||
struct Test
|
||||
{
|
||||
std::wstring_view input;
|
||||
til::some<std::wstring_view, 5> expected;
|
||||
};
|
||||
|
||||
static constexpr std::array tests{
|
||||
Test{ L"", {} },
|
||||
Test{ L"a", { L"a" } },
|
||||
Test{ L"abc", { L"a", L"b", L"c" } },
|
||||
Test{ PAIR L"a" PAIR L"b" PAIR, { PAIR, L"a", PAIR, L"b", PAIR } },
|
||||
Test{ LEADING L"a" LEADING L"b" LEADING, { REPLACEMENT, L"a", REPLACEMENT, L"b", REPLACEMENT } },
|
||||
Test{ TRAILING L"a" TRAILING L"b" TRAILING, { REPLACEMENT, L"a", REPLACEMENT, L"b", REPLACEMENT } },
|
||||
Test{ L"a" TRAILING LEADING L"b", { L"a", REPLACEMENT, REPLACEMENT, L"b" } },
|
||||
};
|
||||
|
||||
for (const auto& t : tests)
|
||||
{
|
||||
auto it = t.expected.begin();
|
||||
const auto end = t.expected.end();
|
||||
|
||||
for (const auto& v : til::utf16_iterator{ t.input })
|
||||
{
|
||||
VERIFY_ARE_NOT_EQUAL(end, it);
|
||||
VERIFY_ARE_EQUAL(*it, v);
|
||||
++it;
|
||||
}
|
||||
|
||||
VERIFY_ARE_EQUAL(end, it);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -33,6 +33,7 @@ SOURCES = \
|
||||
StaticMapTests.cpp \
|
||||
string.cpp \
|
||||
u8u16convertTests.cpp \
|
||||
UnicodeTests.cpp \
|
||||
DefaultResource.rc \
|
||||
|
||||
# These tests are disabled because of a missing symbol.
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<ClCompile Include="string.cpp" />
|
||||
<ClCompile Include="throttled_func.cpp" />
|
||||
<ClCompile Include="u8u16convertTests.cpp" />
|
||||
<ClCompile Include="UnicodeTests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\inc\til\at.h" />
|
||||
@@ -64,6 +65,7 @@
|
||||
<ClInclude Include="..\..\inc\til\throttled_func.h" />
|
||||
<ClInclude Include="..\..\inc\til\ticket_lock.h" />
|
||||
<ClInclude Include="..\..\inc\til\u8u16convert.h" />
|
||||
<ClInclude Include="..\..\inc\til\unicode.h" />
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<ClCompile Include="string.cpp" />
|
||||
<ClCompile Include="throttled_func.cpp" />
|
||||
<ClCompile Include="u8u16convertTests.cpp" />
|
||||
<ClCompile Include="UnicodeTests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\precomp.h" />
|
||||
@@ -110,6 +111,9 @@
|
||||
<ClInclude Include="..\..\inc\til\u8u16convert.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\inc\til\unicode.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="inc">
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include "inc/Utf16Parser.hpp"
|
||||
#include "unicode.hpp"
|
||||
|
||||
// Routine Description:
|
||||
// - Finds the next single collection for the codepoint out of the given UTF-16 string information.
|
||||
// - In simpler terms, it will group UTF-16 surrogate pairs into a single unit or give you a valid single-item UTF-16 character.
|
||||
// - Does not validate UTF-16 input beyond proper leading/trailing character sequences.
|
||||
// Arguments:
|
||||
// - wstr - The UTF-16 string to parse.
|
||||
// Return Value:
|
||||
// - A view into the string given of just the next codepoint unit.
|
||||
std::wstring_view Utf16Parser::ParseNext(std::wstring_view wstr) noexcept
|
||||
{
|
||||
for (size_t pos = 0; pos < wstr.size(); ++pos)
|
||||
{
|
||||
const auto wch = wstr.at(pos);
|
||||
|
||||
// If it's a lead and followed directly by a trail, then return the pair.
|
||||
// If it's not followed directly by the trail, go around again and seek forward.
|
||||
if (IsLeadingSurrogate(wch))
|
||||
{
|
||||
// Try to find the next item... if it isn't there, we'll go around again.
|
||||
const auto posNext = pos + 1;
|
||||
if (posNext < wstr.size())
|
||||
{
|
||||
// If we found it and it's trailing, return the pair.
|
||||
const auto wchNext = wstr.at(posNext);
|
||||
if (IsTrailingSurrogate(wchNext))
|
||||
{
|
||||
return wstr.substr(pos, 2);
|
||||
}
|
||||
}
|
||||
// If we missed either if in any way, we'll fall through and go around again searching for more.
|
||||
}
|
||||
// If it's just a trail at this point, go around again and seek forward.
|
||||
else if (IsTrailingSurrogate(wch))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// If it's neither lead nor trail, then it's < U+10000 and it can be returned as a single wchar_t point.
|
||||
else
|
||||
{
|
||||
return wstr.substr(pos, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// If we get all the way through and there's nothing valid, then this is just a replacement character as it was broken/garbage.
|
||||
return std::wstring_view{ &UNICODE_REPLACEMENT, 1 };
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - formats a utf16 encoded wstring and splits the codepoints into individual collections.
|
||||
// - will drop badly formatted leading/trailing char sequences.
|
||||
// - does not validate utf16 input beyond proper leading/trailing char sequences.
|
||||
// Arguments:
|
||||
// - wstr - the string to parse
|
||||
// Return Value:
|
||||
// - a vector of utf16 codepoints. glyphs that require surrogate pairs will be grouped
|
||||
// together in a vector and codepoints that use only one wchar will be in a vector by themselves.
|
||||
std::vector<std::vector<wchar_t>> Utf16Parser::Parse(std::wstring_view wstr)
|
||||
{
|
||||
std::vector<std::vector<wchar_t>> result;
|
||||
std::vector<wchar_t> sequence;
|
||||
for (const auto wch : wstr)
|
||||
{
|
||||
if (IsLeadingSurrogate(wch))
|
||||
{
|
||||
sequence.clear();
|
||||
sequence.push_back(wch);
|
||||
}
|
||||
else if (IsTrailingSurrogate(wch))
|
||||
{
|
||||
if (!sequence.empty())
|
||||
{
|
||||
sequence.push_back(wch);
|
||||
result.push_back(sequence);
|
||||
sequence.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back({ wch });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
- Utf16Parser.hpp
|
||||
|
||||
Abstract:
|
||||
- Parser for grouping together utf16 codepoints from a string of utf16 encoded text
|
||||
|
||||
Author(s):
|
||||
- Austin Diviness (AustDi) 25-Apr-2018
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Utf16Parser final
|
||||
{
|
||||
public:
|
||||
static std::vector<std::vector<wchar_t>> Parse(std::wstring_view wstr);
|
||||
static std::wstring_view ParseNext(std::wstring_view wstr) noexcept;
|
||||
|
||||
// Routine Description:
|
||||
// - checks if wchar is a utf16 leading surrogate
|
||||
// Arguments:
|
||||
// - wch - the wchar to check
|
||||
// Return Value:
|
||||
// - true if wch is a leading surrogate, false otherwise
|
||||
static constexpr bool IsLeadingSurrogate(const wchar_t wch) noexcept
|
||||
{
|
||||
return wch >= 0xD800 && wch <= 0xDBFF;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - checks if wchar is a utf16 trailing surrogate
|
||||
// Arguments:
|
||||
// - wch - the wchar to check
|
||||
// Return Value:
|
||||
// - true if wch is a trailing surrogate, false otherwise
|
||||
static constexpr bool IsTrailingSurrogate(const wchar_t wch) noexcept
|
||||
{
|
||||
return wch >= 0xDC00 && wch <= 0xDFFF;
|
||||
}
|
||||
};
|
||||
@@ -30,7 +30,6 @@
|
||||
<ClCompile Include="..\UiaTracing.cpp" />
|
||||
<ClCompile Include="..\TermControlUiaTextRange.cpp" />
|
||||
<ClCompile Include="..\TermControlUiaProvider.cpp" />
|
||||
<ClCompile Include="..\Utf16Parser.cpp" />
|
||||
<ClCompile Include="..\Viewport.cpp" />
|
||||
<ClCompile Include="..\WindowBufferSizeEvent.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
@@ -52,7 +51,6 @@
|
||||
<ClInclude Include="..\inc\ThemeUtils.h" />
|
||||
<ClInclude Include="..\inc\utils.hpp" />
|
||||
<ClInclude Include="..\inc\Viewport.hpp" />
|
||||
<ClInclude Include="..\inc\Utf16Parser.hpp" />
|
||||
<ClInclude Include="..\IUiaData.h" />
|
||||
<ClInclude Include="..\IUiaEventDispatcher.h" />
|
||||
<ClInclude Include="..\IUiaTraceable.h" />
|
||||
|
||||
@@ -57,9 +57,6 @@
|
||||
<ClCompile Include="..\GlyphWidth.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Utf16Parser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -110,9 +107,6 @@
|
||||
<ClInclude Include="..\inc\CodepointWidthDetector.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\inc\Utf16Parser.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\inc\GlyphWidth.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -137,9 +131,6 @@
|
||||
<ClInclude Include="..\inc\Viewport.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\inc\Utf16Parser.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\precomp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -41,7 +41,6 @@ SOURCES= \
|
||||
..\WindowBufferSizeEvent.cpp \
|
||||
..\convert.cpp \
|
||||
..\colorTable.cpp \
|
||||
..\Utf16Parser.cpp \
|
||||
..\utils.cpp \
|
||||
..\ThemeUtils.cpp \
|
||||
..\ScreenInfoUiaProviderBase.cpp \
|
||||
|
||||
Reference in New Issue
Block a user