Compare commits

...

7 Commits

Author SHA1 Message Date
Dustin L. Howett
569f2d790c Migrate spelling-0.0.21 changes from main 2022-08-17 16:59:26 -05:00
Mike Griese
f997571762 its so crisp 2022-08-17 16:59:26 -05:00
Mike Griese
ccbf4ffe1c this is a bunch more actions too 2022-08-17 15:20:46 -05:00
Mike Griese
e419c65748 It's totally working, I can't believe this 2022-08-17 13:36:09 -05:00
Mike Griese
46b8cc6d46 This is an interesting idea - allow us to send the Control that raised the event, as a parameter to ShortcutActionDispatch::DoAction 2022-08-17 12:21:20 -05:00
Mike Griese
e1bd3e9685 It was at this point that I realized how fucked I was 2022-08-17 11:48:00 -05:00
Mike Griese
a3d33895b5 LOTS OF PLUMBING, but they go all the way from json to the ControlCore 2022-08-17 11:47:16 -05:00
44 changed files with 1441 additions and 703 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
@@ -109,8 +110,8 @@ memchr
memicmp
MENUCOMMAND
MENUDATA
MENUITEMINFOW
MENUINFO
MENUITEMINFOW
mmeapi
MOUSELEAVE
mov
@@ -157,8 +158,8 @@ rcx
REGCLS
RETURNCMD
rfind
roundf
ROOTOWNER
roundf
RSHIFT
SACL
schandle
@@ -210,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

@@ -29,6 +29,18 @@ namespace winrt
namespace winrt::TerminalApp::implementation
{
TermControl TerminalPage::_senderOrActiveControl(const IInspectable& sender)
{
if (auto arg{ sender.try_as<TermControl>() })
{
return arg;
}
else
{
return _GetActiveControl();
}
}
void TerminalPage::_HandleOpenNewTabDropdown(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
@@ -149,7 +161,7 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_HandleSendInput(const IInspectable& /*sender*/,
void TerminalPage::_HandleSendInput(const IInspectable& sender,
const ActionEventArgs& args)
{
if (args == nullptr)
@@ -158,7 +170,7 @@ namespace winrt::TerminalApp::implementation
}
else if (const auto& realArgs = args.ActionArgs().try_as<SendInputArgs>())
{
if (const auto termControl{ _GetActiveControl() })
if (const auto termControl{ _senderOrActiveControl(sender) })
{
termControl.SendInput(realArgs.Input());
args.Handled(true);
@@ -278,23 +290,23 @@ namespace winrt::TerminalApp::implementation
args.Handled(true);
}
void TerminalPage::_HandleScrollToMark(const IInspectable& /*sender*/,
void TerminalPage::_HandleScrollToMark(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& realArgs = args.ActionArgs().try_as<ScrollToMarkArgs>())
{
_ApplyToActiveControls([&realArgs](auto& control) {
_ApplyToSenderOrActiveControls(sender, [&realArgs](auto& control) {
control.ScrollToMark(realArgs.Direction());
});
}
args.Handled(true);
}
void TerminalPage::_HandleAddMark(const IInspectable& /*sender*/,
void TerminalPage::_HandleAddMark(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& realArgs = args.ActionArgs().try_as<AddMarkArgs>())
{
_ApplyToActiveControls([realArgs](auto& control) {
_ApplyToSenderOrActiveControls(sender, [realArgs](auto& control) {
Control::ScrollMark mark;
if (realArgs.Color())
{
@@ -310,18 +322,18 @@ namespace winrt::TerminalApp::implementation
}
args.Handled(true);
}
void TerminalPage::_HandleClearMark(const IInspectable& /*sender*/,
void TerminalPage::_HandleClearMark(const IInspectable& sender,
const ActionEventArgs& args)
{
_ApplyToActiveControls([](auto& control) {
_ApplyToSenderOrActiveControls(sender, [](auto& control) {
control.ClearMark();
});
args.Handled(true);
}
void TerminalPage::_HandleClearAllMarks(const IInspectable& /*sender*/,
void TerminalPage::_HandleClearAllMarks(const IInspectable& sender,
const ActionEventArgs& args)
{
_ApplyToActiveControls([](auto& control) {
_ApplyToSenderOrActiveControls(sender, [](auto& control) {
control.ClearAllMarks();
});
args.Handled(true);
@@ -1036,14 +1048,14 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_HandleClearBuffer(const IInspectable& /*sender*/,
void TerminalPage::_HandleClearBuffer(const IInspectable& sender,
const ActionEventArgs& args)
{
if (args)
{
if (const auto& realArgs = args.ActionArgs().try_as<ClearBufferArgs>())
{
const auto res = _ApplyToActiveControls([&](auto& control) {
const auto res = _ApplyToSenderOrActiveControls(sender, [&](auto& control) {
control.ClearBuffer(realArgs.Clear());
});
args.Handled(res);
@@ -1068,14 +1080,14 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_HandleAdjustOpacity(const IInspectable& /*sender*/,
void TerminalPage::_HandleAdjustOpacity(const IInspectable& sender,
const ActionEventArgs& args)
{
if (args)
{
if (const auto& realArgs = args.ActionArgs().try_as<AdjustOpacityArgs>())
{
const auto res = _ApplyToActiveControls([&](auto& control) {
const auto res = _ApplyToSenderOrActiveControls(sender, [&](auto& control) {
control.AdjustOpacity(realArgs.Opacity() / 100.0, realArgs.Relative());
});
args.Handled(res);
@@ -1083,40 +1095,40 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_HandleSelectAll(const IInspectable& /*sender*/,
void TerminalPage::_HandleSelectAll(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
if (const auto& control{ _senderOrActiveControl(sender) })
{
control.SelectAll();
args.Handled(true);
}
}
void TerminalPage::_HandleMarkMode(const IInspectable& /*sender*/,
void TerminalPage::_HandleMarkMode(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
if (const auto& control{ _senderOrActiveControl(sender) })
{
control.ToggleMarkMode();
args.Handled(true);
}
}
void TerminalPage::_HandleToggleBlockSelection(const IInspectable& /*sender*/,
void TerminalPage::_HandleToggleBlockSelection(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
if (const auto& control{ _senderOrActiveControl(sender) })
{
const auto handled = control.ToggleBlockSelection();
args.Handled(handled);
}
}
void TerminalPage::_HandleSwitchSelectionEndpoint(const IInspectable& /*sender*/,
void TerminalPage::_HandleSwitchSelectionEndpoint(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
if (const auto& control{ _senderOrActiveControl(sender) })
{
const auto handled = control.SwitchSelectionEndpoint();
args.Handled(handled);

View File

@@ -44,6 +44,7 @@ Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFo
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
_triggerHitToken = _control.TriggerHit({ this, &Pane::_ControlTriggerHitHandler });
// On the first Pane's creation, lookup resources we'll use to theme the
// Pane, including the brushed to use for the focused/unfocused border
@@ -1138,6 +1139,31 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
}
}
void Pane::_ControlTriggerHitHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Microsoft::Terminal::Control::TriggerHitArgs& eventArgs)
{
if (!_IsLeaf())
{
return;
}
if (_profile)
{
auto triggers = _profile.Triggers();
auto trigger = triggers.GetAt(eventArgs.Index());
auto action = trigger.EvaluateMatch(eventArgs.Matches().GetView());
// TODO! this is a horrible layering violation
if (auto currentXamlApp{ winrt::Windows::UI::Xaml::Application::Current().try_as<winrt::TerminalApp::App>() })
{
auto appLogic{ currentXamlApp.Logic() };
if (auto page{ appLogic.GetRoot().try_as<winrt::TerminalApp::TerminalPage>() })
{
page.ActionDispatch().DoAction(_control, action);
}
}
}
}
// Event Description:
// - Called when our control gains focus. We'll use this to trigger our GotFocus
// callback. The tab that's hosting us should have registered a callback which
@@ -1586,6 +1612,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
// Add our new event handler before revoking the old one.
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
_warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler });
_triggerHitToken = _control.TriggerHit({ this, &Pane::_ControlTriggerHitHandler });
// Revoke the old event handlers. Remove both the handlers for the panes
// themselves closing, and remove their handlers for their controls
@@ -1601,6 +1628,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
{
p->_control.ConnectionStateChanged(p->_connectionStateChangedToken);
p->_control.WarningBell(p->_warningBellToken);
p->_control.TriggerHit(p->_triggerHitToken);
}
});
}
@@ -1609,6 +1637,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
remainingChild->Closed(remainingChildClosedToken);
remainingChild->_control.ConnectionStateChanged(remainingChild->_connectionStateChangedToken);
remainingChild->_control.WarningBell(remainingChild->_warningBellToken);
remainingChild->_control.TriggerHit(remainingChild->_triggerHitToken);
// If we or either of our children was focused, we want to take that
// focus from them.
@@ -1690,6 +1719,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
{
p->_control.ConnectionStateChanged(p->_connectionStateChangedToken);
p->_control.WarningBell(p->_warningBellToken);
p->_control.TriggerHit(p->_triggerHitToken);
}
});
}
@@ -2445,6 +2475,8 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
_connectionStateChangedToken.value = 0;
_control.WarningBell(_warningBellToken);
_warningBellToken.value = 0;
_control.TriggerHit(_triggerHitToken);
_triggerHitToken.value = 0;
// Remove our old GotFocus handler from the control. We don't want the
// control telling us that it's now focused, we want it telling its new

View File

@@ -203,6 +203,7 @@ public:
WINRT_CALLBACK(LostFocus, winrt::delegate<std::shared_ptr<Pane>>);
WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler<bool>);
WINRT_CALLBACK(Detached, winrt::delegate<std::shared_ptr<Pane>>);
WINRT_CALLBACK(TriggerAction, winrt::delegate<std::shared_ptr<Pane>>);
private:
struct PanePoint;
@@ -236,6 +237,7 @@ private:
winrt::event_token _firstClosedToken{ 0 };
winrt::event_token _secondClosedToken{ 0 };
winrt::event_token _warningBellToken{ 0 };
winrt::event_token _triggerHitToken{ 0 };
winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker;
winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker;
@@ -289,6 +291,8 @@ private:
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
void _ControlTriggerHitHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Control::TriggerHitArgs& e);
std::pair<float, float> _CalcChildrenSizes(const float fullSize) const;
SnapChildrenSizeResult _CalcSnappedChildrenSizes(const bool widthOrHeight, const float fullSize) const;

View File

@@ -10,11 +10,11 @@ using namespace winrt::Microsoft::Terminal;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::TerminalApp;
#define ACTION_CASE(action) \
case ShortcutAction::action: \
{ \
_##action##Handlers(*this, eventArgs); \
break; \
#define ACTION_CASE(action) \
case ShortcutAction::action: \
{ \
_##action##Handlers(sender, eventArgs); \
break; \
}
namespace winrt::TerminalApp::implementation
@@ -27,7 +27,8 @@ namespace winrt::TerminalApp::implementation
// - actionAndArgs: the ShortcutAction and associated args to raise an event for.
// Return Value:
// - true if we handled the event was handled, else false.
bool ShortcutActionDispatch::DoAction(const ActionAndArgs& actionAndArgs)
bool ShortcutActionDispatch::DoAction(const winrt::Windows::Foundation::IInspectable& sender,
const ActionAndArgs& actionAndArgs)
{
if (!actionAndArgs)
{
@@ -50,4 +51,8 @@ namespace winrt::TerminalApp::implementation
return eventArgs.Handled();
}
bool ShortcutActionDispatch::DoAction(const ActionAndArgs& actionAndArgs)
{
return DoAction(nullptr, actionAndArgs);
}
}

View File

@@ -13,7 +13,7 @@ namespace TerminalAppLocalTests
class KeyBindingsTests;
}
#define DECLARE_ACTION(action) TYPED_EVENT(action, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
#define DECLARE_ACTION(action) TYPED_EVENT(action, winrt::Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::ActionEventArgs);
namespace winrt::TerminalApp::implementation
{
@@ -22,6 +22,8 @@ namespace winrt::TerminalApp::implementation
ShortcutActionDispatch() = default;
bool DoAction(const Microsoft::Terminal::Settings::Model::ActionAndArgs& actionAndArgs);
bool DoAction(const winrt::Windows::Foundation::IInspectable& sender,
const Microsoft::Terminal::Settings::Model::ActionAndArgs& actionAndArgs);
#define ON_ALL_ACTIONS(action) DECLARE_ACTION(action);
ALL_SHORTCUT_ACTIONS

View File

@@ -2,7 +2,7 @@
// Licensed under the MIT license.
#include "../TerminalSettingsModel/AllShortcutActions.h"
#define ACTION_EVENT(name) event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> name
#define ACTION_EVENT(name) event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.ActionEventArgs> name
namespace TerminalApp
{
@@ -10,6 +10,7 @@ namespace TerminalApp
ShortcutActionDispatch();
Boolean DoAction(Microsoft.Terminal.Settings.Model.ActionAndArgs actionAndArgs);
Boolean DoAction(Object sender, Microsoft.Terminal.Settings.Model.ActionAndArgs actionAndArgs);
// When adding a new action, add them to AllShortcutActions.h!
#define ON_ALL_ACTIONS(action) ACTION_EVENT(action);

View File

@@ -136,6 +136,8 @@ namespace winrt::TerminalApp::implementation
void OpenSettingsUI();
void WindowActivated(const bool activated);
TerminalApp::ShortcutActionDispatch ActionDispatch() { return *_actionDispatch; }
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
// -------------------------------- WinRT Events ---------------------------------
@@ -297,6 +299,18 @@ namespace winrt::TerminalApp::implementation
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool _MovePane(const uint32_t tabIdx);
template<typename F>
bool _ApplyToSenderOrActiveControls(const IInspectable& sender, const F f)
{
if (auto control{ sender.try_as<Microsoft::Terminal::Control::TermControl>() })
{
f(control);
return true;
}
else
return _ApplyToActiveControls(f);
}
template<typename F>
bool _ApplyToActiveControls(F f)
{
@@ -453,6 +467,7 @@ namespace winrt::TerminalApp::implementation
winrt::fire_and_forget _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
winrt::Microsoft::Terminal::Control::TermControl _senderOrActiveControl(const winrt::Windows::Foundation::IInspectable& sender);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);

View File

@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TaskbarState.idl";
import "ShortcutActionDispatch.idl";
namespace TerminalApp
{
@@ -48,6 +49,8 @@ namespace TerminalApp
Windows.UI.Xaml.Media.Brush TitlebarBrush { get; };
void WindowActivated(Boolean activated);
ShortcutActionDispatch ActionDispatch { get; };
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;

View File

@@ -130,6 +130,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnPlayMidiNote = std::bind(&ControlCore::_terminalPlayMidiNote, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
_terminal->SetPlayMidiNoteCallback(pfnPlayMidiNote);
auto pfnTrigger = std::bind(&ControlCore::_terminalTrigger, this, std::placeholders::_1, std::placeholders::_2);
_terminal->SetTriggerCallback(pfnTrigger);
// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
@@ -2137,4 +2140,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}
}
void ControlCore::_terminalTrigger(size_t index, const std::wsmatch& matches)
{
if (index > _settings->Triggers().Size())
return;
auto pattern = _settings->Triggers().GetAt(base::saturated_cast<uint32_t>(index));
_TriggerHitHandlers(*this, *winrt::make_self<implementation::TriggerHitArgs>(index, matches));
}
}

View File

@@ -219,6 +219,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
TYPED_EVENT(UpdateSelectionMarkers, IInspectable, Control::UpdateSelectionMarkersEventArgs);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(TriggerHit, IInspectable, Control::TriggerHitArgs);
// clang-format on
private:
@@ -291,6 +292,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _terminalPlayMidiNote(const int noteNumber,
const int velocity,
const std::chrono::microseconds duration);
void _terminalTrigger(size_t index, const std::wsmatch& matches);
#pragma endregion
std::unique_ptr<MidiAudio> _midiAudio;

View File

@@ -154,5 +154,7 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
event Windows.Foundation.TypedEventHandler<Object, OpenHyperlinkEventArgs> OpenHyperlink;
event Windows.Foundation.TypedEventHandler<Object, TriggerHitArgs> TriggerHit;
};
}

View File

@@ -14,3 +14,4 @@
#include "FoundResultsArgs.g.cpp"
#include "ShowWindowArgs.g.cpp"
#include "UpdateSelectionMarkersEventArgs.g.cpp"
#include "TriggerHitArgs.g.cpp"

View File

@@ -14,6 +14,7 @@
#include "FoundResultsArgs.g.h"
#include "ShowWindowArgs.g.h"
#include "UpdateSelectionMarkersEventArgs.g.h"
#include "TriggerHitArgs.g.h"
namespace winrt::Microsoft::Terminal::Control::implementation
{
@@ -169,4 +170,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WINRT_PROPERTY(bool, ClearMarkers, false);
};
struct TriggerHitArgs : public TriggerHitArgsT<TriggerHitArgs>
{
public:
TriggerHitArgs() = default;
TriggerHitArgs(size_t index, const std::wsmatch& matches)
{
_Index = ::base::saturated_cast<uint32_t>(index);
_Matches = winrt::single_threaded_vector<winrt::hstring>();
for (const auto& match : matches)
_Matches.Append(winrt::hstring{ match.str() });
};
WINRT_PROPERTY(uint32_t, Index);
WINRT_PROPERTY(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, Matches);
};
}

View File

@@ -83,4 +83,10 @@ namespace Microsoft.Terminal.Control
{
Boolean ClearMarkers { get; };
}
runtimeclass TriggerHitArgs
{
UInt32 Index { get; };
IVector<String> Matches { get; };
}
}

View File

@@ -142,8 +142,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
PROJECTED_FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable, _core, TaskbarProgressChanged);
PROJECTED_FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable, _core, ConnectionStateChanged);
PROJECTED_FORWARDED_TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs, _core, ShowWindowChanged);
PROJECTED_FORWARDED_TYPED_EVENT(TriggerHit, IInspectable, Control::TriggerHitArgs, _core, TriggerHit);
PROJECTED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs, _interactivity, PasteFromClipboard);
PROJECTED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs, _interactivity, PasteFromClipboard);
TYPED_EVENT(OpenHyperlink, IInspectable, Control::OpenHyperlinkEventArgs);
TYPED_EVENT(RaiseNotice, IInspectable, Control::NoticeEventArgs);

View File

@@ -49,6 +49,8 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
event Windows.Foundation.TypedEventHandler<Object, TriggerHitArgs> TriggerHit;
Boolean CopySelectionToClipboard(Boolean singleLine, Windows.Foundation.IReference<CopyFormat> formats);
void PasteTextFromClipboard();
void SelectAll();

View File

@@ -29,6 +29,7 @@ namespace Microsoft.Terminal.Core
Boolean AutoMarkPrompts;
IVector<String> Triggers;
};
}

View File

@@ -143,6 +143,12 @@ void Terminal::UpdateSettings(ICoreSettings settings)
_startingTabColor = settings.StartingTabColor().Value();
}
_triggers.clear();
for (const auto& trigger : settings.Triggers())
{
_triggers.emplace_back(std::wregex{ trigger.c_str() });
}
// TODO:MSFT:21327402 - if HistorySize has changed, resize the buffer so we
// have a smaller scrollback. We should do this carefully - if the new buffer
// size is smaller than where the mutable viewport currently is, we'll want
@@ -513,6 +519,8 @@ void Terminal::Write(std::wstring_view stringView)
{
_NotifyTerminalCursorPositionChanged();
}
_runTriggers();
}
void Terminal::WritePastedText(std::wstring_view stringView)
@@ -1377,6 +1385,11 @@ void Terminal::SetPlayMidiNoteCallback(std::function<void(const int, const int,
_pfnPlayMidiNote.swap(pfn);
}
void Terminal::SetTriggerCallback(std::function<void(const size_t, const std::wsmatch&)> pfn) noexcept
{
_pfnTriggerCallback.swap(pfn);
}
// Method Description:
// - Sets the cursor to be currently on. On/Off is tracked independently of
// cursor visibility (hidden/visible). On/off is controlled by the cursor
@@ -1638,3 +1651,29 @@ til::color Terminal::GetColorForMark(const Microsoft::Console::VirtualTerminal::
}
}
}
void Terminal::_runTriggers()
{
if (!_pfnTriggerCallback || _triggers.size() == 0)
{
return;
}
const auto cursorPos = _activeBuffer().GetCursor().GetPosition();
// const auto bufferRow = cursorPos.Y;
const auto& row = _activeBuffer().GetRowByOffset(cursorPos.Y);
const auto text = row.GetText();
for (auto i = 0u; i < _triggers.size(); i++)
{
const std::wregex& trigger = _triggers[i];
std::wsmatch matches;
if (std::regex_search(text, matches, trigger))
{
// That regex matched. Bubble it up to the handler.
_pfnTriggerCallback(i, matches);
}
}
}

View File

@@ -217,6 +217,7 @@ public:
void TaskbarProgressChangedCallback(std::function<void()> pfn) noexcept;
void SetShowWindowCallback(std::function<void(bool)> pfn) noexcept;
void SetPlayMidiNoteCallback(std::function<void(const int, const int, const std::chrono::microseconds)> pfn) noexcept;
void SetTriggerCallback(std::function<void(const size_t, const std::wsmatch&)> pfn) noexcept;
void SetCursorOn(const bool isOn);
bool IsCursorBlinkingAllowed() const noexcept;
@@ -314,6 +315,7 @@ private:
std::function<void()> _pfnTaskbarProgressChanged;
std::function<void(bool)> _pfnShowWindowChanged;
std::function<void(const int, const int, const std::chrono::microseconds)> _pfnPlayMidiNote;
std::function<void(const size_t, const std::wsmatch&)> _pfnTriggerCallback;
RenderSettings _renderSettings;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
@@ -401,6 +403,7 @@ private:
std::optional<KeyEventCodes> _lastKeyEventCodes;
std::vector<Microsoft::Console::VirtualTerminal::DispatchTypes::ScrollMark> _scrollMarks;
std::vector<std::wregex> _triggers;
static WORD _ScanCodeFromVirtualKey(const WORD vkey) noexcept;
static WORD _VirtualKeyFromScanCode(const WORD scanCode) noexcept;
@@ -428,6 +431,8 @@ private:
TextBuffer& _activeBuffer() const noexcept;
void _updateUrlDetection();
void _runTriggers();
#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
std::vector<til::inclusive_rect> _GetSelectionRects() const noexcept;

View File

@@ -84,6 +84,8 @@ void Terminal::LineFeed(const bool withReturn)
// row we just came from
_activeBuffer().GetRowByOffset(cursorPos.Y).SetWrapForced(false);
_runTriggers();
cursorPos.Y++;
if (withReturn)
{

View File

@@ -8,6 +8,7 @@
#define BLOCK_TIL
#include <LibraryIncludes.h>
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/Microsoft.Terminal.Core.h"
#include <til.h>

View File

@@ -451,7 +451,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// - input: the string to JSON escape.
// Return Value:
// - the input string escaped properly to be inserted into another json blob.
std::string _escapeForJson(const std::string& input)
static std::string _escapeForJson(const std::string& input)
{
Json::Value inJson{ input };
Json::StreamWriterBuilder builder;

View File

@@ -82,7 +82,8 @@ Author(s):
X(bool, Elevate, "elevate", false) \
X(bool, VtPassthrough, "experimental.connection.passthroughMode", false) \
X(bool, AutoMarkPrompts, "experimental.autoMarkPrompts", false) \
X(bool, ShowMarks, "experimental.showMarksOnScrollbar", false)
X(bool, ShowMarks, "experimental.showMarksOnScrollbar", false) \
X(Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::Trigger>, Triggers, "experimental.triggers", nullptr)
// Intentionally omitted Profile settings:
// * Name

View File

@@ -92,6 +92,7 @@
<ClInclude Include="VsDevShellGenerator.h" />
<ClInclude Include="VsSetupConfiguration.h" />
<ClInclude Include="WslDistroGenerator.h" />
<ClInclude Include="Trigger.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
@@ -165,6 +166,9 @@
<ClCompile Include="VsDevShellGenerator.cpp" />
<ClCompile Include="VsSetupConfiguration.cpp" />
<ClCompile Include="WslDistroGenerator.cpp" />
<ClCompile Include="Trigger.cpp">
<DependentUpon>Profile.idl</DependentUpon>
</ClCompile>
<!-- You _NEED_ to include this file and the jsoncpp IncludePath (below) if
you want to use jsoncpp -->
<ClCompile Include="$(OpenConsoleDir)\dep\jsoncpp\jsoncpp.cpp">

View File

@@ -9,6 +9,7 @@
#include "TerminalSettingsSerializationHelpers.h"
#include "AppearanceConfig.h"
#include "FontConfig.h"
#include "Trigger.h"
#include "Profile.g.cpp"

View File

@@ -3,6 +3,11 @@
import "IAppearanceConfig.idl";
import "FontConfig.idl";
// For triggers, TODO! move to my own file
import "ActionArgs.idl";
#include "IInheritable.idl.h"
#define INHERITABLE_PROFILE_SETTING(Type, Name) \
@@ -11,6 +16,20 @@ import "FontConfig.idl";
namespace Microsoft.Terminal.Settings.Model
{
enum TriggerType
{
MatchRegex = 0,
};
[default_interface] runtimeclass Trigger {
Trigger();
TriggerType Type { get; };
String Match { get; };
// ActionAndArgs ActionAndArgs { get; };
ActionAndArgs EvaluateMatch(IVectorView<String> matches);
}
// This tag is used to identify the context in which the Profile was created
enum OriginTag
{
@@ -87,5 +106,7 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_PROFILE_SETTING(Boolean, Elevate);
INHERITABLE_PROFILE_SETTING(Boolean, AutoMarkPrompts);
INHERITABLE_PROFILE_SETTING(Boolean, ShowMarks);
INHERITABLE_PROFILE_SETTING(IVector<Trigger>, Triggers);
}
}

View File

@@ -283,6 +283,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_Elevate = profile.Elevate();
_AutoMarkPrompts = Feature_ScrollbarMarks::IsEnabled() && profile.AutoMarkPrompts();
_ShowMarks = Feature_ScrollbarMarks::IsEnabled() && profile.ShowMarks();
_Triggers = winrt::single_threaded_vector<winrt::hstring>();
for (const auto& trigger : profile.Triggers())
{
_Triggers->Append(trigger.Match());
}
}
// Method Description:

View File

@@ -112,6 +112,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
INHERITABLE_SETTING(Model::TerminalSettings, Microsoft::Terminal::Core::AdjustTextMode, AdjustIndistinguishableColors, Core::AdjustTextMode::Never);
INHERITABLE_SETTING(Model::TerminalSettings, Windows::Foundation::Collections::IVector<winrt::hstring>, Triggers, nullptr);
// ------------------------ End of Core Settings -----------------------
INHERITABLE_SETTING(Model::TerminalSettings, hstring, ProfileName);

View File

@@ -0,0 +1,259 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Trigger.h"
#include "Trigger.g.cpp"
#include "ActionAndArgs.h"
#include "KeyChordSerialization.h"
#include <LibraryResources.h>
#include "TerminalSettingsSerializationHelpers.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Windows::Foundation::Collections;
using namespace ::Microsoft::Terminal::Settings::Model;
namespace winrt
{
namespace MUX = Microsoft::UI::Xaml;
namespace WUX = Windows::UI::Xaml;
}
static constexpr std::string_view ActionKey{ "command" };
static constexpr std::string_view MatchKey{ "match" };
static constexpr std::string_view sure{ "%d" };
static constexpr std::string_view MatchToken{ "${{match[{}]}}" };
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
com_ptr<Trigger> Trigger::Copy() const
{
auto trigger{ winrt::make_self<Trigger>() };
// trigger->_ActionAndArgs = *get_self<implementation::ActionAndArgs>(_ActionAndArgs)->Copy();
trigger->_originalActionJson = _originalActionJson;
trigger->_Type = _Type;
trigger->_Match = _Match;
return trigger;
}
// Method Description:
// - Deserialize a Command from the `json` object. The json object should
// contain a "name" and "action", and optionally an "icon".
// * "name": string|object - the name of the command to display in the
// command palette. If this is an object, look for the "key" property,
// and try to load the string from our resources instead.
// * "action": string|object - A ShortcutAction, either as a name or as an
// ActionAndArgs serialization. See ActionAndArgs::FromJson for details.
// If this is null, we'll remove this command from the list of commands.
// Arguments:
// - json: the Json::Value to deserialize into a Command
// - warnings: If there were any warnings during parsing, they'll be
// appended to this vector.
// Return Value:
// - the newly constructed Command object.
winrt::com_ptr<Trigger> Trigger::FromJson(const Json::Value& json)
{
auto result = winrt::make_self<Trigger>();
JsonUtils::GetValueForKey(json, MatchKey, result->_Match);
// If we're a nested command, we can ignore the current action.
result->_originalActionJson = json[JsonKey(ActionKey)];
return result;
}
// Function Description:
// - Attempt to parse all the json objects in `json` into new Command
// objects, and add them to the map of commands.
// - If any parsed command has
// the same Name as an existing command in commands, the new one will
// layer on top of the existing one.
// Arguments:
// - commands: a map of Name->Command which new commands should be layered upon.
// - json: A Json::Value containing an array of serialized commands
// Return Value:
// - A vector containing any warnings detected while parsing
std::vector<SettingsLoadWarnings> Trigger::LayerJson(Windows::Foundation::Collections::IVector<Model::Trigger>& triggers,
const Json::Value& json)
{
std::vector<SettingsLoadWarnings> warnings;
for (const auto& value : json)
{
if (value.isObject())
{
try
{
const auto result = Trigger::FromJson(value);
// if (result->ActionAndArgs().Action() == ShortcutAction::Invalid && !result->HasNestedCommands())
// {
// // If there wasn't a parsed command, then try to get the
// // name from the json blob. If that name currently
// // exists in our list of commands, we should remove it.
// const auto name = _nameFromJson(value);
// if (name.has_value() && !name->empty())
// {
// commands.Remove(*name);
// }
// }
// else
// {
// // Override commands with the same name
// commands.Insert(result->Name(), *result);
// }
triggers.Append(*result);
}
CATCH_LOG();
}
}
return warnings;
}
// Function Description:
// - Serialize the Command into an array of json actions
// Arguments:
// - <none>
// Return Value:
// - an array of serialized actions
Json::Value Trigger::ToJson() const
{
//TODO!
// Json::Value cmdList{ Json::ValueType::arrayValue };
// if (_nestedCommand || _IterateOn != ExpandCommandType::None)
// {
// // handle special commands
// // For these, we can trust _originalJson to be correct.
// // In fact, we _need_ to use it here because we don't actually deserialize `iterateOn`
// // until we expand the command.
// cmdList.append(_originalJson);
// }
// else if (_keyMappings.empty())
// {
// // only write out one command
// Json::Value cmdJson{ Json::ValueType::objectValue };
// JsonUtils::SetValueForKey(cmdJson, IconKey, _iconPath);
// JsonUtils::SetValueForKey(cmdJson, NameKey, _name);
// if (_ActionAndArgs)
// {
// cmdJson[JsonKey(ActionKey)] = ActionAndArgs::ToJson(_ActionAndArgs);
// }
// cmdList.append(cmdJson);
// }
// else
// {
// // we'll write out one command per key mapping
// for (auto keys{ _keyMappings.begin() }; keys != _keyMappings.end(); ++keys)
// {
// Json::Value cmdJson{ Json::ValueType::objectValue };
// if (keys == _keyMappings.begin())
// {
// // First iteration also writes icon and name
// JsonUtils::SetValueForKey(cmdJson, IconKey, _iconPath);
// JsonUtils::SetValueForKey(cmdJson, NameKey, _name);
// }
// if (_ActionAndArgs)
// {
// cmdJson[JsonKey(ActionKey)] = ActionAndArgs::ToJson(_ActionAndArgs);
// }
// JsonUtils::SetValueForKey(cmdJson, KeysKey, *keys);
// cmdList.append(cmdJson);
// }
// }
// return cmdList;
return Json::Value{};
}
// Function Description:
// - Helper to escape a string as a json string. This function will also
// trim off the leading and trailing double-quotes, so the output string
// can be inserted directly into another json blob.
// Arguments:
// - input: the string to JSON escape.
// Return Value:
// - the input string escaped properly to be inserted into another json blob.
static std::string _escapeForJson(const std::string& input)
{
Json::Value inJson{ input };
Json::StreamWriterBuilder builder;
builder.settings_["indentation"] = "";
auto out{ Json::writeString(builder, inJson) };
if (out.size() >= 2)
{
// trim off the leading/trailing '"'s
auto ss{ out.substr(1, out.size() - 2) };
return ss;
}
return out;
}
// Method Description:
// - Iterate over all the provided commands, and recursively expand any
// commands with `iterateOn` set. If we successfully generated expanded
// commands for them, then we'll remove the original command, and add all
// the newly generated commands.
// - For more specific implementation details, see _expandCommand.
// Arguments:
// - commands: a map of commands to expand. Newly created commands will be
// inserted into the map to replace the expandable commands.
// - profiles: A list of all the profiles that this command should be expanded on.
// - warnings: If there were any warnings during parsing, they'll be
// appended to this vector.
// Return Value:
// - <none>
Model::ActionAndArgs Trigger::EvaluateMatch(const Windows::Foundation::Collections::IVectorView<winrt::hstring>& matches /*,
Windows::Foundation::Collections::IVector<SettingsLoadWarnings> warnings*/
)
{
std::string errs; // This string will receive any error text from failing to parse.
std::unique_ptr<Json::CharReader> reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() };
// First, get a string for the original Json::Value
auto oldJsonString = _originalActionJson.toStyledString();
auto reParseJson = [&](const auto& newJsonString) -> Model::ActionAndArgs {
// - Now, re-parse the modified value.
Json::Value newJsonValue;
const auto actualDataStart = newJsonString.data();
const auto actualDataEnd = newJsonString.data() + newJsonString.size();
if (!reader->parse(actualDataStart, actualDataEnd, &newJsonValue, &errs))
{
// warnings.Append(SettingsLoadWarnings::FailedToParseCommandJson);
// If we encounter a re-parsing error, just stop processing the rest of the commands.
return false;
}
// Pass the new json back though FromJson, to get the new expanded value.
std::vector<SettingsLoadWarnings> newWarnings;
auto result = ActionAndArgs::FromJson(newJsonValue, newWarnings);
// std::for_each(newWarnings.begin(), newWarnings.end(), [warnings](auto& warn) { warnings.Append(warn); });
return *result;
};
auto newJsonString = oldJsonString;
for (uint32_t i = 0u; i < matches.Size(); i++)
{
auto newNeedle = fmt::format(MatchToken, i);
auto escapedMatch = _escapeForJson(til::u16u8(matches.GetAt(i)));
newJsonString = til::replace_needle_in_haystack(newJsonString,
newNeedle,
escapedMatch);
}
return reParseJson(newJsonString);
}
}

View File

@@ -0,0 +1,102 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- Command.h
Abstract:
- A command represents a single entry in the Command Palette. This is an object
that has a user facing "name" to display to the user, and an associated action
which can be dispatched.
- For more information, see GH#2046, #5400, #5674, and #6635
Author(s):
- Mike Griese - June 2020
--*/
#pragma once
#include "Trigger.g.h"
#include "TerminalWarnings.h"
#include "ActionAndArgs.h"
#include "SettingsTypes.h"
#include "JsonUtils.h"
// fwdecl unittest classes
namespace SettingsModelLocalTests
{
class DeserializationTests;
class TriggerTests;
};
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
struct Trigger : TriggerT<Trigger>
{
Trigger() = default;
com_ptr<Trigger> Copy() const;
static winrt::com_ptr<Trigger> FromJson(const Json::Value& json);
Model::ActionAndArgs EvaluateMatch(const Windows::Foundation::Collections::IVectorView<winrt::hstring>& matches /*,
Windows::Foundation::Collections::IVector<SettingsLoadWarnings> warnings*/
);
static std::vector<SettingsLoadWarnings> LayerJson(Windows::Foundation::Collections::IVector<Model::Trigger>& triggers,
const Json::Value& json);
Json::Value ToJson() const;
winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker propertyChangedRevoker;
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_PROPERTY(TriggerType, Type, TriggerType::MatchRegex);
WINRT_PROPERTY(winrt::hstring, Match, L"");
// WINRT_PROPERTY(Model::ActionAndArgs, ActionAndArgs);
private:
Json::Value _originalActionJson;
friend class SettingsModelLocalTests::DeserializationTests;
friend class SettingsModelLocalTests::TriggerTests;
};
}
namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
{
BASIC_FACTORY(Trigger);
}
namespace Microsoft::Terminal::Settings::Model::JsonUtils
{
using namespace winrt::Microsoft::Terminal::Settings::Model;
// If you get weird linker errors about this not being defined, make sure
// you #include this file in the file that's actually doing the
// de/serializing (e.g. Profile.cpp)
template<>
struct ConversionTrait<Trigger>
{
Trigger FromJson(const Json::Value& json)
{
return *implementation::Trigger::FromJson(json);
}
bool CanConvert(const Json::Value& json) const
{
return json.isObject();
}
Json::Value ToJson(const Trigger& val)
{
return winrt::get_self<implementation::Trigger>(val)->ToJson();
}
std::string TypeDescription() const
{
return "Trigger";
}
};
}

View File

@@ -47,7 +47,8 @@
X(winrt::hstring, StartingTitle) \
X(bool, DetectURLs, true) \
X(bool, VtPassthrough, false) \
X(bool, AutoMarkPrompts)
X(bool, AutoMarkPrompts) \
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, Triggers, nullptr)
// --------------------------- Control Settings ---------------------------
// All of these settings are defined in IControlSettings.