Compare commits

...

46 Commits

Author SHA1 Message Date
Dustin L. Howett
21fa31b3b3 Migrate spelling-0.0.21 changes from main 2020-06-19 11:09:25 -05:00
Dustin L. Howett
bae1077228 Migrate spelling-0.0.19 changes from main 2020-06-19 11:09:25 -05:00
Mike Griese
45243bbee6 Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	src/cascadia/TerminalApp/ActionAndArgs.cpp
2020-06-19 11:09:25 -05:00
Mike Griese
52eb2e5faa Merge commit '827cc42' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	doc/specs/#2046 - Command Palette.md
2020-06-19 11:07:48 -05:00
Mike Griese
8b094fdfde Merge commit 'db518c0' into dev/migrie/f/2046-Command-Palette-v2 2020-06-19 10:59:07 -05:00
Mike Griese
7a94b8f725 stash these tests in progress 2020-06-11 16:29:06 -05:00
Mike Griese
e2f5f75471 start adding tests 2020-06-11 12:40:57 -05:00
Mike Griese
7ac7fd1de9 Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2 2020-06-11 12:15:27 -05:00
Mike Griese
dd684cbca1 implement a weighted ordering for command palette entries 2020-06-10 09:59:55 -05:00
Mike Griese
edc8b557e1 Add much better key chord text to the command palette 2020-06-10 08:53:34 -05:00
Mike Griese
82f968d8d5 If a key is bound to that action, then display the keybinding in the palette 2020-06-09 16:58:51 -05:00
Mike Griese
67c7969879 I couldn't tell you how long this took 2020-06-09 16:30:55 -05:00
Mike Griese
b3d8f0e279 Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2 2020-06-09 12:33:36 -05:00
Mike Griese
d71d8d7b32 Ready for review. 2020-06-04 12:29:22 -05:00
Mike Griese
9d411d405c Make the commands a map, so we can override on "name" 2020-06-04 11:48:38 -05:00
Mike Griese
58be8cd117 Tons of commenting 2020-06-04 11:21:46 -05:00
Mike Griese
487f33ee89 Merge commit '6e6979abe' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	src/cascadia/TerminalApp/ActionAndArgs.cpp
#	src/cascadia/TerminalApp/AppKeyBindingsSerialization.cpp
2020-06-04 10:15:40 -05:00
Mike Griese
829beda501 Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	src/cascadia/TerminalApp/GlobalAppSettings.cpp
#	src/cascadia/TerminalApp/GlobalAppSettings.h
2020-06-04 10:02:40 -05:00
Mike Griese
6e6979abe8 Extract ActionAndArgs::FromJson into it's own class, so it can be re-used later 2020-06-04 09:28:21 -05:00
Mike Griese
1fbe8e415d Turns out, the shadow on the menuflyout isn't my fault, it's on everything that uses MUX 2020-05-29 12:45:39 -05:00
Mike Griese
fa93fdc034 Well, this is neat, and works, but requires 18362 and also casts a shadow on the menuflyout??? 2020-05-29 12:19:04 -05:00
Mike Griese
cf6e1f273a Try to do this with a shadow, but it crashes inexplicably 2020-05-29 11:44:38 -05:00
Mike Griese
99059451d8 Return focus to the active control when closed 2020-05-29 11:29:01 -05:00
Mike Griese
a309191461 Rename private methods, fix wraparound logic 2020-05-29 11:14:56 -05:00
Mike Griese
e1be26b184 Do this in WinRTUtils instead of hackily doing it manually 2020-05-29 09:48:30 -05:00
Mike Griese
bc546dbdb0 Add some stability
Don't die when we encounter an unexpected key
  Reload successfully
2020-05-29 09:42:47 -05:00
Mike Griese
00763fda9e Add duplicate pane to the default commands 2020-05-29 07:47:29 -05:00
Mike Griese
b88be4534b Make sure to scroll the selected item into view 2020-05-29 07:43:12 -05:00
Mike Griese
207666e34d Add a ton of default commands 2020-05-29 07:32:43 -05:00
Mike Griese
62b9a0d1c0 Move the action into it's own sub-object 2020-05-28 16:44:38 -05:00
Mike Griese
02f47f49c3 Make the action names map public, so the ToJson in AKBSerialization can use it 2020-05-28 16:40:04 -05:00
Mike Griese
6905065fcf Merge remote-tracking branch 'origin/master' into dev/migrie/f/2046-Command-Palette-v2
# Conflicts:
#	src/cascadia/TerminalApp/TerminalPage.h
2020-05-28 15:29:23 -05:00
Mike Griese
0416a944a2 Hook up the parsing of ActionAndArgss to the command palette 2020-05-28 15:09:45 -05:00
Mike Griese
3627d8abd5 This should have been in the previous commit 2020-05-28 15:08:57 -05:00
Mike Griese
33a9e32736 Get names from the resources if provided as an object, not a string 2020-05-28 12:56:17 -05:00
Mike Griese
75af4cabbb Hook up all the parsing once again 2020-05-28 12:31:49 -05:00
Mike Griese
43bd483962 Blind port these files from the old branch 2020-05-28 11:26:25 -05:00
Mike Griese
0672812e6f good bot 2020-05-28 10:29:09 -05:00
Mike Griese
f53553f4e4 Merge remote-tracking branch 'origin/master' into dev/migrie/s/5400-CommandPalette-v1 2020-05-28 10:27:58 -05:00
Mike Griese
11130a4895 Add some notes about the advanced tab switcher and how that might interplay with this 2020-05-20 09:15:27 -05:00
Mike Griese
0886e8f12d Merge remote-tracking branch 'origin/master' into dev/migrie/s/5400-CommandPalette-v1 2020-05-20 08:47:50 -05:00
Mike Griese
2e564368c8 Move this section to 'future considerations' 2020-05-07 12:17:00 -05:00
Mike Griese
ead76d7f16 Merge remote-tracking branch 'origin/master' into dev/migrie/s/5400-CommandPalette-v1 2020-05-07 12:11:48 -05:00
Mike Griese
614d1b21d6 last little todos for review 2020-04-30 15:20:25 -05:00
Mike Griese
fe640ff894 move this spec out of drafts/ 2020-04-30 15:03:52 -05:00
Mike Griese
c56eb8fd93 Add a ton of text regarding Commandline Mode vs Action Mode 2020-04-30 15:02:59 -05:00
68 changed files with 3297 additions and 480967 deletions

View File

@@ -1,25 +0,0 @@
<details>
<summary>
:pencil2: Contributor please read this
</summary>
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
:warning: The command is written for posix shells. You can copy the contents of each `perl` command excluding the outer `'` marks and dropping any `'"`/`"'` quotation mark pairs into a file and then run `perl file.pl` from the root of the repository to run the code. Alternatively, you can manually insert the items...
If the listed items are:
* ... **misspelled**, then please *correct* them instead of using the command.
* ... *names*, please add them to `.github/actions/spell-check/dictionary/names.txt`.
* ... APIs, you can add them to a file in `.github/actions/spell-check/dictionary/`.
* ... just things you're using, please add them to an appropriate file in `.github/actions/spell-check/expect/`.
* ... tokens you only need in one place and shouldn't *generally be used*, you can add an item in an appropriate file in `.github/actions/spell-check/patterns/`.
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>
#### :warning: Reviewers
At present, the action that triggered this message will not show its :x: in this PR unless the branch is within this repository.
Thus, you **should** make sure that this comment has been addressed before encouraging the merge bot to merge this PR.

View File

@@ -1,35 +0,0 @@
ACCEPTFILES
ACCESSDENIED
bitfield
bitfields
CLASSNOTAVAILABLE
EXPCMDFLAGS
EXPCMDSTATE
fullkbd
href
IAsync
IBox
IBind
IClass
IComparable
ICustom
IDirect
IExplorer
IMap
IObject
IStorage
LCID
LSHIFT
NCHITTEST
NCLBUTTONDBLCLK
NCRBUTTONDBLCLK
NOAGGREGATION
NOREDIRECTIONBITMAP
oaidl
ocidl
RETURNCMD
rfind
roundf
RSHIFT
SIZENS
tmp

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
powf
sqrtf
isnan

View File

@@ -1,14 +0,0 @@
ACLs
DACL
DACLs
LKG
mfcribbon
microsoft
microsoftonline
osgvsowi
powerrename
powershell
SACLs
tdbuildteamid
vcruntime
visualstudio

View File

@@ -1,63 +0,0 @@
(?:^|/)dirs$
(?:^|/)go\.mod$
(?:^|/)go\.sum$
(?:^|/)package-lock\.json$
(?:^|/)sources(?:|\.dep)$
SUMS$
\.ai$
\.bmp$
\.cer$
\.class$
\.crl$
\.crt$
\.csr$
\.dll$
\.DS_Store$
\.eot$
\.eps$
\.exe$
\.gif$
\.graffle$
\.gz$
\.icns$
\.ico$
\.jar$
\.jpeg$
\.jpg$
\.key$
\.lib$
\.lock$
\.map$
\.min\..
\.mp3$
\.mp4$
\.otf$
\.pbxproj$
\.pdf$
\.pem$
\.png$
\.psd$
\.runsettings$
\.sig$
\.so$
\.svg$
\.svgz$
\.tar$
\.tgz$
\.ttf$
\.woff
\.xcf$
\.xls
\.xpm$
\.yml$
\.zip$
^consolegit2gitfilters\.json$
^dep/
^oss/
^doc/reference/UTF8-torture-test\.txt$
^src/interactivity/onecore/BgfxEngine\.
^src/renderer/wddmcon/WddmConRenderer\.
^src/terminal/parser/ft_fuzzer/VTCommandFuzzer\.cpp$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^\.github/actions/spell-check/
^\.gitignore$

View File

@@ -1,15 +0,0 @@
http
td
www
ecma
rapidtables
WCAG
freedesktop
ycombinator
robertelder
kovidgoyal
leonerd
fixterms
uk
winui
appshellintegration

View File

@@ -1,18 +0,0 @@
https://(?:(?:[-a-zA-Z0-9?&=]*\.|)microsoft\.com)/[-a-zA-Z0-9?&=_#\/.]*
https://aka\.ms/[-a-zA-Z0-9?&=\/_]*
https://www\.itscj\.ipsj\.or\.jp/iso-ir/[-0-9]+\.pdf
https://www\.vt100\.net/docs/[-a-zA-Z0-9#_\/.]*
https://www.w3.org/[-a-zA-Z0-9?&=\/_#]*
https://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
https://[a-z-]+\.githubusercontent\.com/[-a-zA-Z0-9?&=_\/.]*
[Pp]ublicKeyToken="?[0-9a-fA-F]{16}"?
(?:[{"]|UniqueIdentifier>)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(?:[}"]|</UniqueIdentifier)
(?:0[Xx]|\\x|U\+|#)[a-f0-9A-FGgRr]{2,}[Uu]?[Ll]{0,2}\b
microsoft/cascadia-code\@[0-9a-fA-F]{40}
\d+x\d+Logo
Scro\&ll
# selectionInput.cpp
:\\windows\\syste\b
TestUtils::VerifyExpectedString\(tb, L"[^"]+"
hostSm\.ProcessString\(L"[^"]+"
\b([A-Za-z])\1{3,}\b

15
.github/actions/spelling/README.md vendored Normal file
View File

@@ -0,0 +1,15 @@
# check-spelling/check-spelling configuration
File | Purpose | Format | Info
-|-|-|-
[allow/*.txt](allow/) | Add words to the dictionary | one word per line (only letters and `'`s allowed) | [allow](https://github.com/check-spelling/check-spelling/wiki/Configuration#allow)
[reject.txt](reject.txt) | Remove words from the dictionary (after allow) | grep pattern matching whole dictionary words | [reject](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-reject)
[excludes.txt](excludes.txt) | Files to ignore entirely | perl regular expression | [excludes](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-excludes)
[patterns/*.txt](patterns/) | Patterns to ignore from checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[candidate.patterns](candidate.patterns) | Patterns that might be worth adding to [patterns.txt](patterns.txt) | perl regular expression with optional comment block introductions (all matches will be suggested) | [candidates](https://github.com/check-spelling/check-spelling/wiki/Feature:-Suggest-patterns)
[line_forbidden.patterns](line_forbidden.patterns) | Patterns to flag in checked lines | perl regular expression (order matters, first match wins) | [patterns](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-patterns)
[expect/*.txt](expect.txt) | Expected words that aren't in the dictionary | one word per line (sorted, alphabetically) | [expect](https://github.com/check-spelling/check-spelling/wiki/Configuration#expect)
[advice.md](advice.md) | Supplement for GitHub comment when unrecognized words are found | GitHub Markdown | [advice](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice)
Note: you can replace any of these files with a directory by the same name (minus the suffix)
and then include multiple files inside that directory (with that suffix) to merge multiple files together.

48
.github/actions/spelling/advice.md vendored Normal file
View File

@@ -0,0 +1,48 @@
<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details>
<summary>
:pencil2: Contributor please read this
</summary>
By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.
:warning: The command is written for posix shells. If it doesn't work for you, you can manually _add_ (one word per line) / _remove_ items to `expect.txt` and the `excludes.txt` files.
If the listed items are:
* ... **misspelled**, then please *correct* them instead of using the command.
* ... *names*, please add them to `.github/actions/spelling/allow/names.txt`.
* ... APIs, you can add them to a file in `.github/actions/spelling/allow/`.
* ... just things you're using, please add them to an appropriate file in `.github/actions/spelling/expect/`.
* ... tokens you only need in one place and shouldn't *generally be used*, you can add an item in an appropriate file in `.github/actions/spelling/patterns/`.
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>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).
Please add a file path to the `excludes.txt` file matching the containing file.
File paths are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.
`^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
../tree/HEAD/README.md) (on whichever branch you're using).
* well-formed pattern.
If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
try adding it to the `patterns.txt` file.
Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.
Note that patterns can't match multiline strings.
</details>
</details>

View File

@@ -1,6 +1,6 @@
# Dictionaries are lists of words to accept unconditionally
# Allow files are lists of words to accept unconditionally
While check spelling will complain about a whitelisted word
While check spelling will complain about an expected word
which is no longer present, you can include things here even if
they are not otherwise present in the repository.
@@ -8,13 +8,14 @@ E.g., you could include a list of system APIs here, or potential
contributors (so that if a future commit includes their name,
it'll be accepted).
### Files
## Files
| File | Description |
| ---- | ----------- |
| [Dictionary](dictionary.txt) | Primary US English dictionary |
| [Allow](allow.txt) | Supplements to the dictionary |
| [Chinese](chinese.txt) | Chinese words |
| [Japanese](japanese.txt) | Japanese words |
| [Microsoft](microsoft.txt) | Microsoft brand items |
| [Fonts](fonts.txt) | Font names |
| [Names](names.txt) | Names of people |
| [Colors](colors.txt) | Names of color |

108
.github/actions/spelling/allow/allow.txt vendored Normal file
View File

@@ -0,0 +1,108 @@
admins
allcolors
Apc
apc
breadcrumb
breadcrumbs
bsd
calt
ccmp
changelog
clickable
clig
CMMI
copyable
cybersecurity
dalet
Dcs
dcs
dialytika
dje
downside
downsides
dze
dzhe
EDDB
EDDC
Enum'd
Fitt
formattings
FTCS
ftp
fvar
gantt
gcc
geeksforgeeks
ghe
github
gje
godbolt
hostname
hostnames
https
hyperlink
hyperlinking
hyperlinks
iconify
img
inlined
It'd
kje
libfuzzer
libuv
liga
lje
Llast
llvm
Lmid
locl
lol
lorem
Lorigin
maxed
minimalistic
mkmk
mnt
mru
nje
noreply
ogonek
ok'd
overlined
pipeline
postmodern
ptys
qof
qps
rclt
reimplementation
reserialization
reserialize
reserializes
rlig
runtimes
shcha
slnt
Sos
ssh
timeline
timelines
timestamped
TLDR
tokenizes
tonos
toolset
tshe
ubuntu
uiatextrange
UIs
und
unregister
versioned
vsdevcmd
We'd
wildcards
XBox
YBox
yeru
zhe

248
.github/actions/spelling/allow/apis.txt vendored Normal file
View File

@@ -0,0 +1,248 @@
ACCEPTFILES
ACCESSDENIED
acl
aclapi
alignas
alignof
APPLYTOSUBMENUS
appxrecipe
bitfield
bitfields
BUILDBRANCH
BUILDMSG
BUILDNUMBER
BYCOMMAND
BYPOSITION
charconv
CLASSNOTAVAILABLE
CLOSEAPP
cmdletbinding
COLORPROPERTY
colspan
COMDLG
commandlinetoargv
comparand
cstdint
CXICON
CYICON
Dacl
dataobject
dcomp
DERR
dlldata
DNE
DONTADDTORECENT
DWMSBT
DWMWA
DWMWA
DWORDLONG
endfor
ENDSESSION
enumset
environstrings
EXPCMDFLAGS
EXPCMDSTATE
filetime
FILTERSPEC
FORCEFILESYSTEM
FORCEMINIMIZE
frac
fullkbd
futex
GETDESKWALLPAPER
GETHIGHCONTRAST
GETMOUSEHOVERTIME
Hashtable
HIGHCONTRASTON
HIGHCONTRASTW
hotkeys
href
hrgn
HTCLOSE
hwinsta
HWINSTA
IActivation
IApp
IAppearance
IAsync
IBind
IBox
IClass
IComparable
IComparer
IConnection
ICustom
IDialog
IDirect
IExplorer
IFACEMETHOD
IFile
IGraphics
IInheritable
IMap
IMonarch
IObject
iosfwd
IPackage
IPeasant
ISetup
isspace
IStorage
istream
IStringable
ITab
ITaskbar
itow
IUri
IVirtual
KEYSELECT
LCID
llabs
llu
localtime
lround
Lsa
lsass
LSHIFT
LTGRAY
MAINWINDOW
memchr
memicmp
MENUCOMMAND
MENUDATA
MENUINFO
MENUITEMINFOW
mmeapi
MOUSELEAVE
mov
mptt
msappx
MULTIPLEUSE
NCHITTEST
NCLBUTTONDBLCLK
NCMOUSELEAVE
NCMOUSEMOVE
NCRBUTTONDBLCLK
NIF
NIN
NOAGGREGATION
NOASYNC
NOCHANGEDIR
NOPROGRESS
NOREDIRECTIONBITMAP
NOREPEAT
NOTIFYBYPOS
NOTIFYICON
NOTIFYICONDATA
ntprivapi
oaidl
ocidl
ODR
offsetof
ofstream
onefuzz
osver
OSVERSIONINFOEXW
otms
OUTLINETEXTMETRICW
overridable
PACL
PAGESCROLL
PATINVERT
PEXPLICIT
PICKFOLDERS
pmr
ptstr
QUERYENDSESSION
rcx
REGCLS
RETURNCMD
rfind
ROOTOWNER
roundf
RSHIFT
SACL
schandle
semver
serializer
SETVERSION
SHELLEXECUTEINFOW
shobjidl
SHOWHIDE
SHOWMINIMIZED
SHOWTIP
SINGLEUSE
SIZENS
smoothstep
snprintf
spsc
sregex
SRWLOC
SRWLOCK
STDCPP
STDMETHOD
strchr
strcpy
streambuf
strtoul
Stubless
Subheader
Subpage
syscall
SYSTEMBACKDROP
TABROW
TASKBARCREATED
TBPF
THEMECHANGED
tlg
TME
tmp
tmpdir
tolower
toupper
TRACKMOUSEEVENT
TTask
TVal
UChar
UFIELD
ULARGE
UOI
UPDATEINIFILE
userenv
USEROBJECTFLAGS
Viewbox
virtualalloc
wcsstr
wcstoui
winmain
winsta
winstamin
wmemcmp
wpc
WSF
wsregex
wwinmain
xchg
XDocument
XElement
xfacet
xhash
XIcon
xiosbase
xlocale
xlocbuf
xlocinfo
xlocmes
xlocmon
xlocnum
xloctime
XMax
xmemory
XParse
xpath
xstddef
xstring
xtree
xutility
YIcon
YMax

View File

@@ -0,0 +1,117 @@
alice
aliceblue
antiquewhite
blanchedalmond
blueviolet
burlywood
cadetblue
cornflowerblue
cornsilk
cyan
darkblue
darkcyan
darkgoldenrod
darkgray
darkgreen
darkgrey
darkkhaki
darkmagenta
darkolivegreen
darkorange
darkorchid
darkred
darksalmon
darkseagreen
darkslateblue
darkslategray
darkslategrey
darkturquoise
darkviolet
deeppink
deepskyblue
dimgray
dimgrey
dodgerblue
firebrick
floralwhite
forestgreen
gainsboro
ghostwhite
greenyellow
hotpink
indian
indianred
lavenderblush
lawngreen
lemonchiffon
lightblue
lightcoral
lightcyan
lightgoldenrod
lightgoldenrodyellow
lightgray
lightgreen
lightgrey
lightpink
lightsalmon
lightseagreen
lightskyblue
lightslateblue
lightslategray
lightslategrey
lightsteelblue
lightyellow
limegreen
mediumaquamarine
mediumblue
mediumorchid
mediumpurple
mediumseagreen
mediumslateblue
mediumspringgreen
mediumturquoise
mediumvioletred
midnightblue
mintcream
mistyrose
navajo
navajowhite
navyblue
oldlace
olivedrab
orangered
palegoldenrod
palegreen
paleturquoise
palevioletred
papayawhip
peachpuff
peru
powderblue
rebecca
rebeccapurple
rosybrown
royalblue
saddlebrown
sandybrown
seagreen
sienna
skyblue
slateblue
slategray
slategrey
springgreen
steelblue
violetred
webgray
webgreen
webgrey
webmaroon
webpurple
whitesmoke
xaroon
xray
xreen
xrey
xurple
yellowgreen

View File

@@ -1,8 +1,10 @@
Consolas
emoji
emojis
Extralight
Gabriola
Iosevka
MDL
Monofur
Segoe
wght

11
.github/actions/spelling/allow/math.txt vendored Normal file
View File

@@ -0,0 +1,11 @@
atan
CPrime
HBar
HPrime
isnan
LPrime
LStep
powf
RSub
sqrtf
ULP

View File

@@ -0,0 +1,85 @@
ACLs
ADMINS
advapi
altform
altforms
appendwttlogging
appx
appxbundle
appxerror
appxmanifest
ATL
backplating
bitmaps
BOMs
CPLs
cpptools
cppvsdbg
CPRs
cryptbase
DACL
DACLs
defaultlib
diffs
disposables
dotnetfeed
DTDs
DWINRT
enablewttlogging
Intelli
IVisual
libucrt
libucrtd
LKG
LOCKFILE
Lxss
mfcribbon
microsoft
microsoftonline
MSAA
msixbundle
MSVC
MSVCP
muxc
netcore
Onefuzz
osgvsowi
PFILETIME
pgc
pgo
pgosweep
powerrename
powershell
propkey
pscustomobject
QWORD
regedit
robocopy
SACLs
sdkddkver
Shobjidl
Skype
SRW
sxs
Sysinternals
sysnative
systemroot
taskkill
tasklist
tdbuildteamid
ucrt
ucrtd
unvirtualized
VCRT
vcruntime
Virtualization
visualstudio
vscode
VSTHRD
winsdkver
wlk
wslpath
wtl
wtt
wttlog
Xamarin

View File

@@ -1,43 +1,66 @@
Anup
austdi
arkthur
Ballmer
bhoj
Bhojwani
Bluloco
carlos
dhowett
Diviness
dsafa
duhowett
DXP
ekg
eryksun
ethanschoonover
Firefox
Gatta
glsl
Gravell
Grie
Griese
Hernan
Howett
Illhardt
iquilezles
italo
jantari
jerrysh
Kaiyu
kimwalisch
KMehrain
KODELIFE
Kodelife
Kourosh
kowalczyk
leonmsft
Lepilleur
lhecker
lukesampson
Macbook
Manandhar
masserano
mbadolato
Mehrain
menger
mgravell
michaelniksa
michkap
migrie
mikegr
mikemaccana
miloush
miniksa
niksa
nvaccess
nvda
oising
oldnewthing
opengl
osgwiki
pabhojwa
panos
paulcam
pauldotknopf
PGP
@@ -45,11 +68,18 @@ Pham
Rincewind
rprichard
Schoonover
shadertoy
Shomnipotence
simioni
Somuah
sonph
sonpham
stakx
talo
thereses
Walisch
WDX
Wellons
Wirt
Wojciech
zadjii

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

117
.github/actions/spelling/excludes.txt vendored Normal file
View File

@@ -0,0 +1,117 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-excludes
(?:(?i)\.png$)
(?:^|/)(?i)COPYRIGHT
(?:^|/)(?i)LICEN[CS]E
(?:^|/)3rdparty/
(?:^|/)dirs$
(?:^|/)go\.mod$
(?:^|/)go\.sum$
(?:^|/)package(?:-lock|)\.json$
(?:^|/)sources(?:|\.dep)$
(?:^|/)vendor/
\.a$
\.ai$
\.avi$
\.bmp$
\.bz2$
\.cer$
\.class$
\.crl$
\.crt$
\.csr$
\.dll$
\.docx?$
\.drawio$
\.DS_Store$
\.eot$
\.eps$
\.exe$
\.gif$
\.gitattributes$
\.graffle$
\.gz$
\.icns$
\.ico$
\.jar$
\.jks$
\.jpeg$
\.jpg$
\.key$
\.lib$
\.lock$
\.map$
\.min\..
\.mod$
\.mp3$
\.mp4$
\.o$
\.ocf$
\.otf$
\.pbxproj$
\.pdf$
\.pem$
\.png$
\.psd$
\.pyc$
\.runsettings$
\.s$
\.sig$
\.so$
\.svg$
\.svgz$
\.svgz?$
\.tar$
\.tgz$
\.tiff?$
\.ttf$
\.vsdx$
\.wav$
\.webm$
\.webp$
\.woff
\.woff2?$
\.xcf$
\.xls
\.xlsx?$
\.xpm$
\.yml$
\.zip$
^\.github/actions/spelling/
^\.github/fabricbot.json$
^\.gitignore$
^\Q.git-blame-ignore-revs\E$
^\Q.github/workflows/spelling.yml\E$
^\Qdoc/reference/windows-terminal-logo.ans\E$
^\Qsamples/ConPTY/EchoCon/EchoCon/EchoCon.vcxproj.filters\E$
^\Qsrc/host/exe/Host.EXE.vcxproj.filters\E$
^\Qsrc/host/ft_host/chafa.txt\E$
^\Qsrc/tools/closetest/CloseTest.vcxproj.filters\E$
^\XamlStyler.json$
^build/config/
^consolegit2gitfilters\.json$
^dep/
^doc/reference/master-sequence-list.csv$
^doc/reference/UTF8-torture-test\.txt$
^oss/
^src/host/ft_uia/run\.bat$
^src/host/runft\.bat$
^src/host/runut\.bat$
^src/interactivity/onecore/BgfxEngine\.
^src/renderer/atlas/
^src/renderer/wddmcon/WddmConRenderer\.
^src/terminal/adapter/ut_adapter/run\.bat$
^src/terminal/parser/delfuzzpayload\.bat$
^src/terminal/parser/ft_fuzzer/run\.bat$
^src/terminal/parser/ft_fuzzer/VTCommandFuzzer\.cpp$
^src/terminal/parser/ft_fuzzwrapper/run\.bat$
^src/terminal/parser/ut_parser/Base64Test.cpp$
^src/terminal/parser/ut_parser/run\.bat$
^src/tools/integrity/packageuwp/ConsoleUWP\.appxSources$
^src/tools/lnkd/lnkd\.bat$
^src/tools/pixels/pixels\.bat$
^src/tools/texttests/fira\.txt$
^src/tools/U8U16Test/(?:fr|ru|zh)\.txt$
^src/types/ut_types/UtilsTests.cpp$
^tools/ReleaseEngineering/ServicingPipeline.ps1$
ignore$
SUMS$

View File

@@ -1,21 +1,31 @@
abcde
abcdef
ABCDEFG
ABCDEFGH
AAAa
AAAAA
AAAAAAAAAAAAA
AAAAAABBBBBBCCC
AAAAABBBBBBCCC
abcd
abcd
ABCDEFGHIJ
abcdefghijk
ABCDEFGHIJKLMNO
abcdefghijklmnop
ABCDEFGHIJKLMNOPQRST
abcdefghijklmnopqrstuvwxyz
ABCG
ABE
BBBBBBBBBBBBBBDDDD
abf
BBBBB
BBBBBBBB
BBBBBCCC
BBBBCCCCC
BBGGRR
EFG
EFGh
QQQQQQQQQQABCDEFGHIJ
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
qrstuvwxyz
qwerty
QWERTYUIOP
qwertyuiopasdfg
YYYYYYYDDDDDDDDDDD
ZAAZZ
@@ -27,3 +37,4 @@ ZYXWVUT
ZZBBZ
ZZZBB
ZZZBZ
ZZZZZ

View File

@@ -0,0 +1,6 @@
WCAG
winui
appshellintegration
mdtauk
gfycat
Guake

View File

@@ -0,0 +1,62 @@
# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere
# \bm_data\b
# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test,
# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want
# to use this:
#\bfit\(
# s.b. GitHub
\bGithub\b
# s.b. GitLab
\bGitlab\b
# s.b. JavaScript
\bJavascript\b
# s.b. Microsoft
\bMicroSoft\b
# s.b. another
\ban[- ]other\b
# s.b. greater than
\bgreater then\b
# s.b. into
#\sin to\s
# s.b. opt-in
\sopt in\s
# s.b. less than
\bless then\b
# s.b. otherwise
\bother[- ]wise\b
# s.b. nonexistent
\bnon existing\b
\b[Nn]o[nt][- ]existent\b
# s.b. preexisting
[Pp]re[- ]existing
# s.b. preempt
[Pp]re[- ]empt\b
# s.b. preemptively
[Pp]re[- ]emptively
# s.b. reentrancy
[Rr]e[- ]entrancy
# s.b. reentrant
[Rr]e[- ]entrant
# s.b. workaround(s)
#\bwork[- ]arounds?\b
# Reject duplicate words
\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s

View File

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

12
.github/actions/spelling/reject.txt vendored Normal file
View File

@@ -0,0 +1,12 @@
^attache$
^attacher$
^attachers$
benefitting
occurences?
^dependan.*
^oer$
Sorce
^[Ss]pae.*
^untill$
^untilling$
^wether.*

View File

@@ -1,20 +0,0 @@
name: Spell checking
on:
push:
schedule:
# * is a special character in YAML so you have to quote this string
- cron: '15 * * * *'
jobs:
build:
name: Spell checking
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.0.0
with:
fetch-depth: 5
- uses: check-spelling/check-spelling@0.0.16-alpha
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
bucket: .github/actions
project: spell-check

134
.github/workflows/spelling2.yml vendored Normal file
View File

@@ -0,0 +1,134 @@
# spelling.yml is blocked per https://github.com/check-spelling/check-spelling/security/advisories/GHSA-g86g-chm8-7r2p
name: Spell checking
# Comment management is handled through a secondary job, for details see:
# https://github.com/check-spelling/check-spelling/wiki/Feature%3A-Restricted-Permissions
#
# `jobs.comment-push` runs when a push is made to a repository and the `jobs.spelling` job needs to make a comment
# (in odd cases, it might actually run just to collapse a commment, but that's fairly rare)
# it needs `contents: write` in order to add a comment.
#
# `jobs.comment-pr` runs when a pull_request is made to a repository and the `jobs.spelling` job needs to make a comment
# or collapse a comment (in the case where it had previously made a comment and now no longer needs to show a comment)
# it needs `pull-requests: write` in order to manipulate those comments.
# Updating pull request branches is managed via comment handling.
# For details, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-expect-list
#
# These elements work together to make it happen:
#
# `on.issue_comment`
# This event listens to comments by users asking to update the metadata.
#
# `jobs.update`
# This job runs in response to an issue_comment and will push a new commit
# to update the spelling metadata.
#
# `with.experimental_apply_changes_via_bot`
# Tells the action to support and generate messages that enable it
# to make a commit to update the spelling metadata.
#
# `with.ssh_key`
# In order to trigger workflows when the commit is made, you can provide a
# secret (typically, a write-enabled github deploy key).
#
# For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key
on:
push:
branches:
- "**"
tags-ignore:
- "**"
pull_request_target:
branches:
- "**"
tags-ignore:
- "**"
types:
- 'opened'
- 'reopened'
- 'synchronize'
issue_comment:
types:
- 'created'
jobs:
spelling:
name: Spell checking
permissions:
contents: read
pull-requests: read
actions: read
outputs:
followup: ${{ steps.spelling.outputs.followup }}
runs-on: ubuntu-latest
if: "contains(github.event_name, 'pull_request') || github.event_name == 'push'"
concurrency:
group: spelling-${{ github.event.pull_request.number || github.ref }}
# note: If you use only_check_changed_files, you do not want cancel-in-progress
cancel-in-progress: true
steps:
- name: check-spelling
id: spelling
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-push:
name: Report (Push)
# If your workflow isn't running on push, you can remove this job
runs-on: ubuntu-latest
needs: spelling
permissions:
contents: write
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.21
with:
checkout: true
spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }}
comment-pr:
name: Report (PR)
# If you workflow isn't running on pull_request*, you can remove this job
runs-on: ubuntu-latest
needs: spelling
permissions:
pull-requests: write
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.21
with:
checkout: true
spell_check_this: check-spelling/spell-check-this@prerelease
task: ${{ needs.spelling.outputs.followup }}

View File

@@ -786,3 +786,4 @@ Spec: Introduce a mini-specification for localized resource use from JSON [#5280
[#3327]: https://github.com/microsoft/terminal/issues/3327
[#3753]: https://github.com/microsoft/terminal/pulls/3753
[#5888]: https://github.com/microsoft/terminal/pulls/5888

View File

@@ -0,0 +1,208 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "../TerminalApp/CascadiaSettings.h"
#include "JsonTestClass.h"
#include "TestUtils.h"
using namespace Microsoft::Console;
using namespace TerminalApp;
using namespace winrt::TerminalApp;
using namespace winrt::Microsoft::Terminal::Settings;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
namespace TerminalAppLocalTests
{
// TODO:microsoft/terminal#3838:
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
// an updated TAEF that will let us install framework packages when the test
// package is deployed. Until then, these tests won't deploy in CI.
class CommandTests : public JsonTestClass
{
// Use a custom AppxManifest to ensure that we can activate winrt types
// from our test. This property will tell taef to manually use this as
// the AppxManifest for this test class.
// This does not yet work for anything XAML-y. See TabTests.cpp for more
// details on that.
BEGIN_TEST_CLASS(CommandTests)
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
END_TEST_CLASS()
TEST_METHOD(ManyCommandsSameAction);
TEST_METHOD(LayerCommand);
TEST_METHOD(TestSplitPaneArgs);
TEST_METHOD(TestResourceKeyName);
TEST_CLASS_SETUP(ClassSetup)
{
InitializeJsonReader();
return true;
}
};
void CommandTests::ManyCommandsSameAction()
{
const std::string commands0String{ R"([ { "name":"action0", "action": "copy" } ])" };
const std::string commands1String{ R"([ { "name":"action1", "action": { "action": "copy", "singleLine": false } } ])" };
const std::string commands2String{ R"([
{ "name":"action2", "action": "paste" },
{ "name":"action3", "action": "paste" }
])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
const auto commands1Json = VerifyParseSucceeded(commands1String);
const auto commands2Json = VerifyParseSucceeded(commands2String);
std::map<winrt::hstring, Command> commands;
VERIFY_ARE_EQUAL(0u, commands.size());
{
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
}
VERIFY_ARE_EQUAL(1u, commands.size());
{
auto warnings = implementation::Command::LayerJson(commands, commands1Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
}
VERIFY_ARE_EQUAL(2u, commands.size());
{
auto warnings = implementation::Command::LayerJson(commands, commands2Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
}
VERIFY_ARE_EQUAL(4u, commands.size());
}
void CommandTests::LayerCommand()
{
// Each one of the commands in this test should layer upon the previous, overriding the action.
const std::string commands0String{ R"([ { "name":"action0", "action": "copy" } ])" };
const std::string commands1String{ R"([ { "name":"action0", "action": "paste" } ])" };
const std::string commands2String{ R"([ { "name":"action0", "action": "newTab" } ])" };
const std::string commands3String{ R"([ { "name":"action0", "action": null } ])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
const auto commands1Json = VerifyParseSucceeded(commands1String);
const auto commands2Json = VerifyParseSucceeded(commands2String);
const auto commands3Json = VerifyParseSucceeded(commands3String);
std::map<winrt::hstring, Command> commands;
VERIFY_ARE_EQUAL(0u, commands.size());
{
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(1u, commands.size());
auto command = commands.at(L"action0");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::CopyText, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<CopyTextArgs>();
VERIFY_IS_NOT_NULL(realArgs);
}
{
auto warnings = implementation::Command::LayerJson(commands, commands1Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(1u, commands.size());
auto command = commands.at(L"action0");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::PasteText, command.Action().Action());
VERIFY_IS_NULL(command.Action().Args());
}
{
auto warnings = implementation::Command::LayerJson(commands, commands2Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(1u, commands.size());
auto command = commands.at(L"action0");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::NewTab, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<NewTabArgs>();
VERIFY_IS_NOT_NULL(realArgs);
}
{
// This last command should "unbind" the action.
auto warnings = implementation::Command::LayerJson(commands, commands3Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(0u, commands.size());
}
}
void CommandTests::TestSplitPaneArgs()
{
// This is the same as KeyBindingsTests::TestSplitPaneArgs, but with
// looking up the action and it's args from a map of commands, instead
// of from keybindings.
const std::string commands0String{ R"([
{ "name": "command0", "action": { "action": "splitPane", "split": null } },
{ "name": "command1", "action": { "action": "splitPane", "split": "vertical" } },
{ "name": "command2", "action": { "action": "splitPane", "split": "horizontal" } },
{ "name": "command3", "action": { "action": "splitPane", "split": "none" } },
{ "name": "command4", "action": { "action": "splitPane" } },
{ "name": "command5", "action": { "action": "splitPane", "split": "auto" } },
{ "name": "command6", "action": { "action": "splitPane", "split": "foo" } }
])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
std::map<winrt::hstring, Command> commands;
VERIFY_ARE_EQUAL(0u, commands.size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(7u, commands.size());
{
auto command = commands.at(L"command0");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Automatic, realArgs.SplitStyle());
}
{
auto command = commands.at(L"command1");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<SplitPaneArgs>();
VERIFY_IS_NOT_NULL(realArgs);
// Verify the args have the expected value
VERIFY_ARE_EQUAL(winrt::TerminalApp::SplitState::Vertical, realArgs.SplitStyle());
}
}
void CommandTests::TestResourceKeyName()
{
// Each one of the commands in this test should layer upon the previous, overriding the action.
const std::string commands0String{ R"([ { "name": { "key": "DuplicateTabCommandKey"}, "action": "copy" } ])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
std::map<winrt::hstring, Command> commands;
VERIFY_ARE_EQUAL(0u, commands.size());
{
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(1u, commands.size());
// NOTE: We're relying on DuplicateTabCommandKey being defined as
// "Duplicate Tab" here. If that string changes in our resources,
// this test will break.
auto command = commands.at(L"Duplicate Tab");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.Action());
VERIFY_ARE_EQUAL(ShortcutAction::CopyText, command.Action().Action());
const auto& realArgs = command.Action().Args().try_as<CopyTextArgs>();
VERIFY_IS_NOT_NULL(realArgs);
}
}
}

View File

@@ -60,6 +60,7 @@
<ClCompile Include="ProfileTests.cpp" />
<ClCompile Include="ColorSchemeTests.cpp" />
<ClCompile Include="KeyBindingsTests.cpp" />
<ClCompile Include="CommandTests.cpp" />
<ClCompile Include="TabTests.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>

View File

@@ -34,6 +34,38 @@ static constexpr std::string_view MoveFocusKey{ "moveFocus" };
static constexpr std::string_view FindKey{ "find" };
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
static constexpr std::string_view ActionKey{ "action" };
// This key is reserved to remove a keybinding, instead of mapping it to an action.
static constexpr std::string_view UnboundKey{ "unbound" };
static constexpr std::string_view CopyTextKey{ "copy" };
static constexpr std::string_view PasteTextKey{ "paste" };
static constexpr std::string_view OpenNewTabDropdownKey{ "openNewTabDropdown" };
static constexpr std::string_view DuplicateTabKey{ "duplicateTab" };
static constexpr std::string_view NewTabKey{ "newTab" };
static constexpr std::string_view NewWindowKey{ "newWindow" };
static constexpr std::string_view CloseWindowKey{ "closeWindow" };
static constexpr std::string_view CloseTabKey{ "closeTab" };
static constexpr std::string_view ClosePaneKey{ "closePane" };
static constexpr std::string_view SwitchtoTabKey{ "switchToTab" };
static constexpr std::string_view NextTabKey{ "nextTab" };
static constexpr std::string_view PrevTabKey{ "prevTab" };
static constexpr std::string_view AdjustFontSizeKey{ "adjustFontSize" };
static constexpr std::string_view ResetFontSizeKey{ "resetFontSize" };
static constexpr std::string_view ScrollupKey{ "scrollUp" };
static constexpr std::string_view ScrolldownKey{ "scrollDown" };
static constexpr std::string_view ScrolluppageKey{ "scrollUpPage" };
static constexpr std::string_view ScrolldownpageKey{ "scrollDownPage" };
static constexpr std::string_view SwitchToTabKey{ "switchToTab" };
static constexpr std::string_view OpenSettingsKey{ "openSettings" }; // TODO GH#2557: Add args for OpenSettings
static constexpr std::string_view SplitPaneKey{ "splitPane" };
static constexpr std::string_view ResizePaneKey{ "resizePane" };
static constexpr std::string_view MoveFocusKey{ "moveFocus" };
static constexpr std::string_view FindKey{ "find" };
static constexpr std::string_view ToggleFullscreenKey{ "toggleFullscreen" };
static constexpr std::string_view ToggleCommandPaletteKey{ "toggleCommandPalette" };
namespace winrt::TerminalApp::implementation
{
// Specifically use a map here over an unordered_map. We want to be able to
@@ -69,7 +101,8 @@ namespace winrt::TerminalApp::implementation
{ ToggleFullscreenKey, ShortcutAction::ToggleFullscreen },
{ SplitPaneKey, ShortcutAction::SplitPane },
{ UnboundKey, ShortcutAction::Invalid },
{ FindKey, ShortcutAction::Find }
{ FindKey, ShortcutAction::Find },
{ ToggleCommandPaletteKey, ShortcutAction::ToggleCommandPalette },
};
using ParseResult = std::tuple<IActionArgs, std::vector<::TerminalApp::SettingsLoadWarnings>>;

View File

@@ -12,6 +12,7 @@ namespace winrt::TerminalApp::implementation
std::vector<::TerminalApp::SettingsLoadWarnings>& warnings);
ActionAndArgs() = default;
GETSET_PROPERTY(TerminalApp::ShortcutAction, Action, TerminalApp::ShortcutAction::Invalid);
GETSET_PROPERTY(IActionArgs, Args, nullptr);
};

View File

@@ -361,7 +361,8 @@ namespace winrt::TerminalApp::implementation
if (otherAsUs)
{
return otherAsUs->_SplitStyle == _SplitStyle &&
otherAsUs->_TerminalArgs == _TerminalArgs &&
(otherAsUs->_TerminalArgs ? otherAsUs->_TerminalArgs.Equals(_TerminalArgs) :
otherAsUs->_TerminalArgs == _TerminalArgs) &&
otherAsUs->_SplitMode == _SplitMode;
}
return false;

View File

@@ -237,4 +237,11 @@ namespace winrt::TerminalApp::implementation
ToggleFullscreen();
args.Handled(true);
}
void TerminalPage::_HandleToggleCommandPalette(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{
CommandPalette().ToggleVisibility();
args.Handled(true);
}
}

View File

@@ -55,8 +55,12 @@ namespace winrt::TerminalApp::implementation
{
for (auto& kv : _keyShortcuts)
{
if (kv.second.Action() == actionAndArgs.Action() &&
kv.second.Args().Equals(actionAndArgs.Args()))
auto action = kv.second.Action();
auto args = kv.second.Args();
auto actionMatched = action == actionAndArgs.Action();
auto argsMatched = args ? args.Equals(actionAndArgs.Args()) : args == actionAndArgs.Args();
if (actionMatched &&
argsMatched)
{
return kv.first;
}

View File

@@ -0,0 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Command.h"
#include "Command.g.cpp"
namespace winrt::TerminalApp::implementation
{
}

View File

@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "Command.g.h"
#include "TerminalWarnings.h"
#include "..\inc\cppwinrt_utils.h"
namespace winrt::TerminalApp::implementation
{
struct Command : CommandT<Command>
{
Command() = default;
static winrt::com_ptr<Command> FromJson(const Json::Value& json, std::vector<::TerminalApp::SettingsLoadWarnings>& warnings);
static std::vector<::TerminalApp::SettingsLoadWarnings> LayerJson(std::map<winrt::hstring, winrt::TerminalApp::Command>& commands,
const Json::Value& json);
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Name, _PropertyChangedHandlers);
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, IconPath, _PropertyChangedHandlers);
OBSERVABLE_GETSET_PROPERTY(winrt::TerminalApp::ActionAndArgs, Action, _PropertyChangedHandlers);
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, KeyChordText, _PropertyChangedHandlers);
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(Command);
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "../ShortcutActionDispatch.idl";
namespace TerminalApp
{
[default_interface] runtimeclass Command : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
Command();
String Name;
String IconPath;
ActionAndArgs Action;
String KeyChordText;
}
}

View File

@@ -0,0 +1,338 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "CommandPalette.h"
#include "CommandPalette.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
namespace winrt::TerminalApp::implementation
{
CommandPalette::CommandPalette()
{
InitializeComponent();
_filteredActions = winrt::single_threaded_observable_vector<winrt::TerminalApp::Command>();
_allActions = winrt::single_threaded_vector<winrt::TerminalApp::Command>();
if (CommandPaletteShadow())
{
// Hook up the shadow on the command palette to the backdrop that
// will actually show it. This needs to be done at runtime, and only
// if the shadow actually exists. ThemeShadow isn't supported below
// version 18362.
CommandPaletteShadow().Receivers().Append(ShadowBackdrop());
// "raise" the command palette up by 16 units, so it will cast a shadow.
Backdrop().Translation({ 0, 0, 16 });
}
}
// Method Description:
// - Toggles the visibility of the command palette. This will auto-focus the
// input box within the palette.
// - TODO GH#TODO: When we add support for commandline mode, accept a parameter here
// for which mode we should enter in.
void CommandPalette::ToggleVisibility()
{
const bool isVisible = Visibility() == Visibility::Visible;
if (!isVisible)
{
// Become visible
Visibility(Visibility::Visible);
_SearchBox().Focus(FocusState::Programmatic);
_FilteredActionsView().SelectedIndex(0);
}
else
{
// Raise an event to return control to the Terminal.
_close();
}
}
// Method Description:
// - Moves the focus up or down the list of commands. If we're att the top,
// we'll loop around to the bottom, and vice-versa.
// Arguments:
// - moveDown: if true, we're attempting to move to the next item in the
// list. Otherwise, we're attempting to move to the previous.
// Return Value:
// - <none>
void CommandPalette::_selectNextItem(const bool moveDown)
{
const auto selected = _FilteredActionsView().SelectedIndex();
const int numItems = ::base::saturated_cast<int>(_FilteredActionsView().Items().Size());
// Wraparound math. By adding numItems and then calculating modulo numItems,
// we clamp the values to the range [0, numItems) while still supporting moving
// upward from 0 to numItems - 1.
const auto newIndex = ((numItems + selected + (moveDown ? 1 : -1)) % numItems);
_FilteredActionsView().SelectedIndex(newIndex);
_FilteredActionsView().ScrollIntoView(_FilteredActionsView().SelectedItem());
}
// Method Description:
// - Process keystrokes in the input box. This is used for moving focus up
// and down the list of commands in Action mode, and for executing
// commands in both Action mode and Commandline mode.
// Arguments:
// - e: the KeyRoutedEventArgs containing info about the keystroke.
// Return Value:
// - <none>
void CommandPalette::_keyDownHandler(IInspectable const& /*sender*/,
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
{
auto key = e.OriginalKey();
if (key == VirtualKey::Up)
{
// Action Mode: Move focus to the next item in the list.
_selectNextItem(false);
e.Handled(true);
}
else if (key == VirtualKey::Down)
{
// Action Mode: Move focus to the previous item in the list.
_selectNextItem(true);
e.Handled(true);
}
else if (key == VirtualKey::Enter)
{
// Action Mode: Dispatch the action of the selected command.
if (const auto selectedItem = _FilteredActionsView().SelectedItem())
{
if (const auto data = selectedItem.try_as<Command>())
{
const auto actionAndArgs = data.Action();
_dispatch.DoAction(actionAndArgs);
_close();
}
}
e.Handled(true);
}
else if (key == VirtualKey::Escape)
{
// Action Mode: Dismiss the palette.
_close();
}
}
// Method Description:
// - Event handler for when the text in the input box changes. In Action
// Mode, we'll update the list of displayed commands, and select the first one.
// Arguments:
// - <unused>
// Return Value:
// - <none>
void CommandPalette::_filterTextChanged(IInspectable const& /*sender*/,
Windows::UI::Xaml::RoutedEventArgs const& /*args*/)
{
_updateFilteredActions();
_FilteredActionsView().SelectedIndex(0);
}
Collections::IObservableVector<Command> CommandPalette::FilteredActions()
{
return _filteredActions;
}
void CommandPalette::SetActions(Collections::IVector<TerminalApp::Command> const& actions)
{
_allActions = actions;
_updateFilteredActions();
}
// Method Description:
// - Update our list of filtered actions to reflect the current contents of
// the input box. For more details on which commands will be displayed,
// see `_filterMatchesName`.
// Arguments:
// - <none>
// Return Value:
// - <none>
void CommandPalette::_updateFilteredActions()
{
_filteredActions.Clear();
auto searchText = _SearchBox().Text();
const bool addAll = searchText.empty();
// If there's no filter text, then just add all the commands in order to the list.
if (addAll)
{
for (auto action : _allActions)
{
_filteredActions.Append(action);
}
return;
}
// Here, there was some filter text.
// Show these actions in a weighted order.
// - Matching the first character of a word, then the first char of a
// subsequent word seems better than just "the order they appear in
// the list".
// - TODO GH#TODO:"Recently used commands" ordering also seems valuable.
auto compare = [searchText](const Command& left, const Command& right) {
const int leftWeight = _getWeight(left.Name(), searchText);
const int rightWeight = _getWeight(right.Name(), searchText);
return leftWeight < rightWeight;
};
// Use a priority queue to order commands so that "better" matches
// appear first in the list. The ordering will be determined by the
// match weight produced by _getWeight.
std::priority_queue<Command, std::vector<Command>, decltype(compare)> heap(compare);
for (auto action : _allActions)
{
if (CommandPalette::_filterMatchesName(searchText, action.Name()))
{
heap.push(action);
}
}
// Remove everything in-order from the queue, and add to the list of
// filtered actions.
while (!heap.empty())
{
_filteredActions.Append(heap.top());
heap.pop();
}
}
// Function Description:
// - Determine if a command with the given `name` should be shown if the
// input box contains the string `searchText`. If all the characters of
// search text appear in order in `name`, then this fuction will return
// true. There can be any number of characters separating consecutive
// characters in searchText.
// * For example:
// "name": "New Tab"
// "name": "Close Tab"
// "name": "Close Pane"
// "name": "[-] Split Horizontal"
// "name": "[ | ] Split Vertical"
// "name": "Next Tab"
// "name": "Prev Tab"
// "name": "Open Settings"
// "name": "Open Media Controls"
// * "open" should return both "**Open** Settings" and "**Open** Media Controls".
// * "Tab" would return "New **Tab**", "Close **Tab**", "Next **Tab**" and "Prev
// **Tab**".
// * "P" would return "Close **P**ane", "[-] S**p**lit Horizontal", "[ | ]
// S**p**lit Vertical", "**P**rev Tab", "O**p**en Settings" and "O**p**en Media
// Controls".
// * "sv" would return "[ | ] Split Vertical" (by matching the **S** in
// "Split", then the **V** in "Vertical").
// Arguments:
// - searchText: the string of text to search for in `name`
// - name: the name to check
// Return Value:
// - true if name contained all the characters of searchText
bool CommandPalette::_filterMatchesName(const winrt::hstring& searchText, const winrt::hstring& name)
{
std::wstring lowercaseSearchText{ searchText.c_str() };
std::wstring lowercaseName{ name.c_str() };
std::transform(lowercaseSearchText.begin(), lowercaseSearchText.end(), lowercaseSearchText.begin(), std::towlower);
std::transform(lowercaseName.begin(), lowercaseName.end(), lowercaseName.begin(), std::towlower);
const wchar_t* namePtr = lowercaseName.c_str();
const wchar_t* endOfName = lowercaseName.c_str() + lowercaseName.size();
for (const auto& wch : lowercaseSearchText)
{
while (wch != *namePtr)
{
// increment the character to look at in the name string
namePtr++;
if (namePtr >= endOfName)
{
// If we are at the end of the name string, we haven't found all the search chars
return false;
}
}
}
return true;
}
// Function Description:
// - Calculates a "weighting" by which should be used to order a command
// name relative to other names, given a specific search string.
// Currently, this is based off of two factors:
// * The weight is incremented once for each matched character of the
// search text.
// * If a matching character from the search text was found at the start
// of a word in the name, then we increment the weight again.
// * For example, for a search string "sp", we want "Split Pane" to
// appear in the list before "Close Pane"
// Arguments:
// - searchText: the string of text to search for in `name`
// - name: the name to check
// Return Value:
// - the relative weight of this match
int CommandPalette::_getWeight(const winrt::hstring& searchText,
const winrt::hstring& name)
{
std::wstring lowercaseSearchText{ searchText.c_str() };
std::wstring lowercaseName{ name.c_str() };
std::transform(lowercaseSearchText.begin(), lowercaseSearchText.end(), lowercaseSearchText.begin(), std::towlower);
std::transform(lowercaseName.begin(), lowercaseName.end(), lowercaseName.begin(), std::towlower);
int totalWeight = 0;
bool lastCharWasSpace = true;
const wchar_t* namePtr = lowercaseName.c_str();
const wchar_t* endOfName = lowercaseName.c_str() + lowercaseName.size();
for (const auto& wch : lowercaseSearchText)
{
while (wch != *namePtr)
{
// increment the character to look at in the name string
namePtr++;
if (namePtr >= endOfName)
{
// If we are at the end of the name string, we haven't found all the search chars
return totalWeight;
}
lastCharWasSpace = *namePtr == L' ';
}
// We found the char, increment weight
totalWeight++;
totalWeight += lastCharWasSpace ? 1 : 0;
}
return totalWeight;
}
void CommandPalette::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch)
{
_dispatch = dispatch;
}
// Method Description:
// - Dismiss the command palette. This will:
// * select all the current text in the input box
// * set our visibility to Hidden
// * raise our Closed event, so the page can return focus to the active Terminal
// Arguments:
// - <none>
// Return Value:
// - <none>
void CommandPalette::_close()
{
Visibility(Visibility::Collapsed);
// TODO: Do we want to clear the text box each time we close the dialog? Or leave it?
// I think if we decide to leave it, we should auto-select all the text
// in it, so a user can start typing right away, or continue with the
// current selection.
// _SearchBox().Text(L"");
_closeHandlers(*this, RoutedEventArgs{});
}
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(CommandPalette, Closed, _closeHandlers, TerminalApp::CommandPalette, winrt::Windows::UI::Xaml::RoutedEventArgs);
}

View File

@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "winrt/Microsoft.UI.Xaml.Controls.h"
#include "CommandPalette.g.h"
#include "../../cascadia/inc/cppwinrt_utils.h"
namespace winrt::TerminalApp::implementation
{
struct CommandPalette : CommandPaletteT<CommandPalette>
{
CommandPalette();
Windows::Foundation::Collections::IObservableVector<TerminalApp::Command> FilteredActions();
void SetActions(Windows::Foundation::Collections::IVector<TerminalApp::Command> const& actions);
void ToggleVisibility();
void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(Closed, _closeHandlers, TerminalApp::CommandPalette, winrt::Windows::UI::Xaml::RoutedEventArgs);
private:
friend struct CommandPaletteT<CommandPalette>; // for Xaml to bind events
Windows::Foundation::Collections::IObservableVector<TerminalApp::Command> _filteredActions{ nullptr };
Windows::Foundation::Collections::IVector<TerminalApp::Command> _allActions{ nullptr };
winrt::TerminalApp::ShortcutActionDispatch _dispatch;
void _filterTextChanged(Windows::Foundation::IInspectable const& sender,
Windows::UI::Xaml::RoutedEventArgs const& args);
void _keyDownHandler(Windows::Foundation::IInspectable const& sender,
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
void _selectNextItem(const bool moveDown);
void _updateFilteredActions();
static bool _filterMatchesName(const winrt::hstring& searchText, const winrt::hstring& name);
static int _getWeight(const winrt::hstring& searchText, const winrt::hstring& name);
void _close();
};
}
namespace winrt::TerminalApp::factory_implementation
{
struct CommandPalette : CommandPaletteT<CommandPalette, implementation::CommandPalette>
{
};
}

View File

@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "../Command.idl";
namespace TerminalApp
{
[default_interface] runtimeclass CommandPalette : Windows.UI.Xaml.Controls.Grid
{
CommandPalette();
Windows.Foundation.Collections.IObservableVector<Command> FilteredActions { get; };
void SetActions(Windows.Foundation.Collections.IVector<Command> actions);
void ToggleVisibility();
void SetDispatch(ShortcutActionDispatch dispatch);
event Windows.Foundation.TypedEventHandler<CommandPalette, Windows.UI.Xaml.RoutedEventArgs> Closed;
}
}

View File

@@ -0,0 +1,113 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information. -->
<Grid
x:Class="TerminalApp.CommandPalette"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TerminalApp"
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:Windows10version1903="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract, 8)"
mc:Ignorable="d">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="9*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- ThemeShadow is only on 18362. This "Windows10version1903" bit adds it
conditionally -->
<Grid.Resources>
<Windows10version1903:ThemeShadow x:Name="CommandPaletteShadow" />
</Grid.Resources>
<Grid
x:Name="ShadowBackdrop"
Background="Transparent"
Grid.Column="1"
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
</Grid>
<Grid
x:Name="Backdrop"
Background="{ThemeResource SystemChromeMediumLowColor}"
CornerRadius="{ThemeResource ControlCornerRadius}"
Margin="8"
Grid.Column="1"
Grid.Row="0"
MaxWidth="400"
MaxHeight="400"
Windows10version1903:Shadow="{StaticResource CommandPaletteShadow}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox
Grid.Row="0"
x:Uid="CommandPalette_SearchBox"
x:Name="_SearchBox"
Margin="8"
TextChanged="_filterTextChanged"
KeyDown="_keyDownHandler"
Text="">
</TextBox>
<ListView
Grid.Row="1"
x:Name="_FilteredActionsView"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
SelectionMode="Single"
CanReorderItems="False"
AllowDrop="False"
ItemsSource="{x:Bind FilteredActions}">
<ItemsControl.ItemTemplate >
<DataTemplate x:DataType="local:Command">
<!-- This HorizontalContentAlignment="Stretch" is important
to make sure it takes the entire width of the line -->
<ListViewItem HorizontalContentAlignment="Stretch">
<Grid HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- TODO: Add Icon to command palette entries, in column 0 -->
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind Name, Mode=OneWay}" />
<TextBlock Grid.Column="2"
Foreground="{ThemeResource SystemControlForegroundBaseMediumBrush}"
FontSize="12"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="{x:Bind KeyChordText, Mode=OneWay}" />
</Grid>
</ListViewItem>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
</Grid>
</Grid>

View File

@@ -0,0 +1,165 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Command.h"
#include "Utils.h"
#include "ActionAndArgs.h"
#include <LibraryResources.h>
using namespace winrt::Microsoft::Terminal::Settings;
using namespace winrt::TerminalApp;
static constexpr std::string_view NameKey{ "name" };
static constexpr std::string_view IconPathKey{ "iconPath" };
static constexpr std::string_view ActionKey{ "action" };
static constexpr std::string_view ArgsKey{ "args" };
namespace winrt::TerminalApp::implementation
{
// Function Description:
// - attempt to get the name of this command from the provided json object.
// * If the "name" property is a string, return that value.
// * If the "name" property is an object, attempt to lookup the string
// resource specified by the "key" property, to support localizable
// command names.
// Arguments:
// - json: The Json::Value representing the command object we should get the name for.
// Return Value:
// - the empty string if we couldn't find a name, otherwise the command's name.
winrt::hstring _nameFromJson(const Json::Value& json)
{
if (const auto name{ json[JsonKey(NameKey)] })
{
if (name.isObject())
{
try
{
if (const auto keyJson{ name[JsonKey("key")] })
{
// Make sure the key is present before we try
// loading it. Otherwise we'll crash
const auto resourceKey = GetWstringFromJson(keyJson);
if (HasLibraryResourceWithName(resourceKey))
{
return GetLibraryResourceString(resourceKey);
}
}
}
CATCH_LOG();
}
else if (name.isString())
{
return winrt::to_hstring(name.asString());
}
}
return L"";
}
// Method Description:
// - Deserialize an 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.
// * "iconPath": string? - the path to an icon to use with this command entry
// 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<Command> Command::FromJson(const Json::Value& json,
std::vector<::TerminalApp::SettingsLoadWarnings>& warnings)
{
auto result = winrt::make_self<Command>();
result->_setName(_nameFromJson(json));
if (result->_Name.empty())
{
return nullptr;
}
// TODO GH#TODO: iconPath not implemented quite yet. Can't seem to get the binding quite right.
if (const auto iconPathJson{ json[JsonKey(IconPathKey)] })
{
result->_setIconPath(winrt::to_hstring(iconPathJson.asString()));
}
if (const auto actionJson{ json[JsonKey(ActionKey)] })
{
auto actionAndArgs = ActionAndArgs::FromJson(actionJson, warnings);
if (actionAndArgs)
{
result->_setAction(*actionAndArgs);
}
else
{
// Something like
// { name: "foo", action: "unbound" }
// will _remove_ the "foo" command, by returning null here.
return nullptr;
}
}
else
{
// { name: "foo", action: null } will land in this case, which
// should also be used for unbinding.
return nullptr;
}
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<::TerminalApp::SettingsLoadWarnings> Command::LayerJson(std::map<winrt::hstring, winrt::TerminalApp::Command>& commands,
const Json::Value& json)
{
std::vector<::TerminalApp::SettingsLoadWarnings> warnings;
for (const auto& value : json)
{
if (value.isObject())
{
try
{
auto result = Command::FromJson(value, warnings);
if (result)
{
// Override commands with the same name
commands.insert_or_assign(result->Name(), *result);
}
else
{
// 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(json);
if (!name.empty())
{
commands.erase(name);
}
}
}
CATCH_LOG();
}
}
return warnings;
}
}

View File

@@ -7,7 +7,6 @@
#include "../../inc/DefaultSettings.h"
#include "Utils.h"
#include "JsonUtils.h"
#include <sstream>
using namespace TerminalApp;
using namespace winrt::Microsoft::Terminal::Settings;
@@ -18,6 +17,7 @@ using namespace ::Microsoft::Console;
using namespace winrt::Microsoft::UI::Xaml::Controls;
static constexpr std::string_view KeybindingsKey{ "keybindings" };
static constexpr std::string_view CommandsKey{ "commands" };
static constexpr std::string_view DefaultProfileKey{ "defaultProfile" };
static constexpr std::string_view AlwaysShowTabsKey{ "alwaysShowTabs" };
static constexpr std::string_view InitialRowsKey{ "initialRows" };
@@ -228,6 +228,14 @@ void GlobalAppSettings::LayerJson(const Json::Value& json)
JsonUtils::GetBool(json, DebugFeaturesKey, _DebugFeaturesEnabled);
JsonUtils::GetBool(json, EnableStartupTaskKey, _StartOnUserLogin);
if (auto commandsArray{ json[JsonKey(CommandsKey)] })
{
auto warnings = winrt::TerminalApp::implementation::Command::LayerJson(_commands, commandsArray);
// It's possible that the user provided commands have some warnings
// in them, similar to the keybindings.
_keybindingsWarnings.insert(_keybindingsWarnings.end(), warnings.begin(), warnings.end());
}
}
// Method Description:
@@ -365,3 +373,8 @@ std::vector<TerminalApp::SettingsLoadWarnings> GlobalAppSettings::GetKeybindings
{
return _keybindingsWarnings;
}
const std::map<winrt::hstring, winrt::TerminalApp::Command>& GlobalAppSettings::GetCommands() const noexcept
{
return _commands;
}

View File

@@ -16,6 +16,7 @@ Author(s):
#pragma once
#include "AppKeyBindings.h"
#include "ColorScheme.h"
#include "Command.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
@@ -54,6 +55,8 @@ public:
std::vector<TerminalApp::SettingsLoadWarnings> GetKeybindingsWarnings() const;
const std::map<winrt::hstring, winrt::TerminalApp::Command>& GetCommands() const noexcept;
// These are implemented manually to handle the string/GUID exchange
// by higher layers in the app.
void DefaultProfile(const GUID defaultProfile) noexcept;
@@ -79,7 +82,6 @@ public:
GETSET_PROPERTY(bool, SoftwareRendering, false);
GETSET_PROPERTY(bool, ForceVTInput, false);
GETSET_PROPERTY(bool, DebugFeaturesEnabled); // default value set in constructor
GETSET_PROPERTY(bool, StartOnUserLogin, false);
private:
@@ -90,6 +92,7 @@ private:
std::vector<::TerminalApp::SettingsLoadWarnings> _keybindingsWarnings;
std::unordered_map<std::wstring, ColorScheme> _colorSchemes;
std::map<winrt::hstring, winrt::TerminalApp::Command> _commands;
static winrt::Windows::UI::Xaml::ElementTheme _ParseTheme(const std::wstring& themeString) noexcept;

View File

@@ -347,4 +347,74 @@
<value>Command Prompt</value>
<comment>This is the name of "Command Prompt", as localized in Windows. The localization here should match the one in the Windows product for "Command Prompt"</comment>
</data>
<data name="CommandPalette_SearchBox.PlaceholderText" xml:space="preserve">
<value>Type a command name...</value>
</data>
<data name="CloseWindowCommandKey" xml:space="preserve">
<value>Close Window</value>
</data>
<data name="ToggleFullscreenCommandKey" xml:space="preserve">
<value>Toggle Fullscreen</value>
</data>
<data name="OpenNewTabDropdownCommandKey" xml:space="preserve">
<value>Open New Tab Dropdown</value>
</data>
<data name="OpenSettingsCommandKey" xml:space="preserve">
<value>Open Settings</value>
</data>
<data name="FindCommandKey" xml:space="preserve">
<value>Find</value>
</data>
<data name="NewTabCommandKey" xml:space="preserve">
<value>New Tab</value>
</data>
<data name="DuplicateTabCommandKey" xml:space="preserve">
<value>Duplicate Tab</value>
</data>
<data name="DuplicatePaneCommandKey" xml:space="preserve">
<value>Duplicate Pane</value>
</data>
<data name="NextTabCommandKey" xml:space="preserve">
<value>Next Tab</value>
</data>
<data name="PrevTabCommandKey" xml:space="preserve">
<value>Prev Tab</value>
</data>
<data name="ClosePaneCommandKey" xml:space="preserve">
<value>Close Pane</value>
</data>
<data name="SplitHorizontalCommandKey" xml:space="preserve">
<value>Split Pane Horizontally</value>
</data>
<data name="SplitVerticalCommandKey" xml:space="preserve">
<value>Split Pane Vertically</value>
</data>
<data name="CopyTextCommandKey" xml:space="preserve">
<value>Copy Text</value>
</data>
<data name="PasteCommandKey" xml:space="preserve">
<value>Paste</value>
</data>
<data name="ScrollDownCommandKey" xml:space="preserve">
<value>Scroll Down One Line</value>
</data>
<data name="ScrollDownPageCommandKey" xml:space="preserve">
<value>Scroll Down One Page</value>
</data>
<data name="ScrollUpCommandKey" xml:space="preserve">
<value>Scroll Up One Line</value>
</data>
<data name="ScrollUpPageCommandKey" xml:space="preserve">
<value>Scroll Up One Page</value>
</data>
<data name="IncreaseFontSizeCommandKey" xml:space="preserve">
<value>Increase Font Size</value>
</data>
<data name="DecreaseFontSizeCommandKey" xml:space="preserve">
<value>Decrease Font Size</value>
</data>
<data name="ResetFontSizeCommandKey" xml:space="preserve">
<value>Reset Font Size</value>
</data>
</root>

View File

@@ -159,6 +159,11 @@ namespace winrt::TerminalApp::implementation
_ToggleFullscreenHandlers(*this, *eventArgs);
break;
}
case ShortcutAction::ToggleCommandPalette:
{
_ToggleCommandPaletteHandlers(*this, *eventArgs);
break;
}
default:
return false;
}

View File

@@ -23,30 +23,31 @@ namespace winrt::TerminalApp::implementation
bool DoAction(const ActionAndArgs& actionAndArgs);
// clang-format off
TYPED_EVENT(CopyText, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(PasteText, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(OpenNewTabDropdown,TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(DuplicateTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(NewTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(NewWindow, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(CloseWindow, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(CloseTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ClosePane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(SwitchToTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(NextTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(PrevTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(SplitPane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(AdjustFontSize, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ResetFontSize, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollUp, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollDown, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollUpPage, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollDownPage, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(OpenSettings, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ResizePane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(CopyText, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(PasteText, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(OpenNewTabDropdown, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(DuplicateTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(NewTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(NewWindow, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(CloseWindow, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(CloseTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ClosePane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(SwitchToTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(NextTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(PrevTab, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(SplitPane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(AdjustFontSize, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ResetFontSize, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollUp, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollDown, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollUpPage, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ScrollDownPage, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(OpenSettings, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ResizePane, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
TYPED_EVENT(ToggleCommandPalette, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs);
// clang-format on
private:

View File

@@ -35,7 +35,8 @@ namespace TerminalApp
MoveFocus,
Find,
ToggleFullscreen,
OpenSettings
OpenSettings,
ToggleCommandPalette
};
[default_interface] runtimeclass ActionAndArgs {
@@ -73,5 +74,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> Find;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> MoveFocus;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ToggleFullscreen;
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, ActionEventArgs> ToggleCommandPalette;
}
}

View File

@@ -14,6 +14,7 @@
#include <winrt/Windows.Storage.h>
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
#include "KeyChordSerialization.h"
#include "AzureCloudShellGenerator.h" // For AzureConnectionType
#include "TelnetGenerator.h" // For TelnetConnectionType
#include "TabRowControl.h"
@@ -43,19 +44,74 @@ namespace winrt
namespace winrt::TerminalApp::implementation
{
// Method Description:
// - Handles the special case of providing a text override for the UI shortcut due to VK_OEM issue.
// Looks at the flags from the KeyChord modifiers and provides a concatenated string value of all
// in the same order that XAML would put them as well.
// Return Value:
// - a string representation of the key modifiers for the shortcut
//NOTE: This needs to be localized with https://github.com/microsoft/terminal/issues/794 if XAML framework issue not resolved before then
static std::wstring _FormatOverrideShortcutText(Settings::KeyModifiers modifiers)
{
std::wstring buffer{ L"" };
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Ctrl))
{
buffer += L"Ctrl+";
}
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Shift))
{
buffer += L"Shift+";
}
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Alt))
{
buffer += L"Alt+";
}
return buffer;
}
TerminalPage::TerminalPage() :
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::Tab>() }
{
InitializeComponent();
}
void TerminalPage::SetSettings(std::shared_ptr<::TerminalApp::CascadiaSettings> settings, bool needRefreshUI)
winrt::fire_and_forget TerminalPage::SetSettings(std::shared_ptr<::TerminalApp::CascadiaSettings> settings,
bool needRefreshUI)
{
_settings = settings;
if (needRefreshUI)
{
_RefreshUIForSettingsReload();
}
auto weakThis{ get_weak() };
co_await winrt::resume_foreground(Dispatcher());
if (auto page{ weakThis.get() })
{
// Update the command palette when settings reload
auto commandsCollection = winrt::single_threaded_vector<winrt::TerminalApp::Command>();
for (auto& nameAndCommand : _settings->GlobalSettings().GetCommands())
{
auto command = nameAndCommand.second;
// If there's a keybinding that's bound to exactly this command,
// then get the string for that keychord and display it as a
// part of the command in the UI. Each Command's KeyChordText is
// unset by default, so we don't need to worry about clearing it
// if there isn't a key associated with it.
auto keyChord{ _settings->GetKeybindings().GetKeyBindingForActionWithArgs(command.Action()) };
if (keyChord)
{
command.KeyChordText(KeyChordSerialization::ToString(keyChord));
}
commandsCollection.Append(command);
}
CommandPalette().SetActions(commandsCollection);
}
}
void TerminalPage::Create()
@@ -151,6 +207,9 @@ namespace winrt::TerminalApp::implementation
_tabContent.SizeChanged({ this, &TerminalPage::_OnContentSizeChanged });
CommandPalette().SetDispatch(*_actionDispatch);
CommandPalette().Closed({ this, &TerminalPage::_CommandPaletteClosed });
// Once the page is actually laid out on the screen, trigger all our
// startup actions. Things like Panes need to know at least how big the
// window will be, so they can subdivide that space.
@@ -755,6 +814,7 @@ namespace winrt::TerminalApp::implementation
_actionDispatch->Find({ this, &TerminalPage::_HandleFind });
_actionDispatch->ResetFontSize({ this, &TerminalPage::_HandleResetFontSize });
_actionDispatch->ToggleFullscreen({ this, &TerminalPage::_HandleToggleFullscreen });
_actionDispatch->ToggleCommandPalette({ this, &TerminalPage::_HandleToggleCommandPalette });
}
// Method Description:
@@ -1343,35 +1403,6 @@ namespace winrt::TerminalApp::implementation
return { L"Windows Terminal" };
}
// Method Description:
// - Handles the special case of providing a text override for the UI shortcut due to VK_OEM issue.
// Looks at the flags from the KeyChord modifiers and provides a concatenated string value of all
// in the same order that XAML would put them as well.
// Return Value:
// - a string representation of the key modifiers for the shortcut
//NOTE: This needs to be localized with https://github.com/microsoft/terminal/issues/794 if XAML framework issue not resolved before then
static std::wstring _FormatOverrideShortcutText(Settings::KeyModifiers modifiers)
{
std::wstring buffer{ L"" };
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Ctrl))
{
buffer += L"Ctrl+";
}
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Shift))
{
buffer += L"Shift+";
}
if (WI_IsFlagSet(modifiers, Settings::KeyModifiers::Alt))
{
buffer += L"Alt+";
}
return buffer;
}
// Method Description:
// - Takes a MenuFlyoutItem and a corresponding KeyChord value and creates the accelerator for UI display.
// Takes into account a special case for an error condition for a comma
@@ -2016,6 +2047,16 @@ namespace winrt::TerminalApp::implementation
// TODO GH#3327: Look at what to do with the NC area when we have XAML theming
}
void TerminalPage::_CommandPaletteClosed(const IInspectable& /*sender*/,
const RoutedEventArgs& /*eventArgs*/)
{
// Return focus to the active control
if (auto index{ _GetFocusedTabIndex() })
{
_GetStrongTabImpl(index.value())->SetFocused(true);
}
}
// -------------------------------- WinRT Events ---------------------------------
// Winrt events need a method for adding a callback to the event and removing the callback.
// These macros will define them both for you.

View File

@@ -32,7 +32,7 @@ namespace winrt::TerminalApp::implementation
public:
TerminalPage();
void SetSettings(std::shared_ptr<::TerminalApp::CascadiaSettings> settings, bool needRefreshUI);
winrt::fire_and_forget SetSettings(std::shared_ptr<::TerminalApp::CascadiaSettings> settings, bool needRefreshUI);
void Create();
@@ -172,6 +172,8 @@ namespace winrt::TerminalApp::implementation
void _CompleteInitialization();
void _CommandPaletteClosed(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
void _HandleOpenNewTabDropdown(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
@@ -197,6 +199,8 @@ namespace winrt::TerminalApp::implementation
void _HandleFind(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleResetFontSize(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleToggleFullscreen(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleToggleCommandPalette(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
// Make sure to hook new actions up in _RegisterActionCallbacks!
#pragma endregion
friend class TerminalAppLocalTests::TabTests;

View File

@@ -53,5 +53,12 @@ the MIT License. See LICENSE in the project root for license information. -->
DefaultButton="Primary"
PrimaryButtonClick="_CloseWarningPrimaryButtonOnClick">
</ContentDialog>
<local:CommandPalette
x:Name="CommandPalette"
Grid.Row="1"
Visibility="Collapsed"
VerticalAlignment="Top" />
</Grid>
</Page>

View File

@@ -337,5 +337,38 @@
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+=" },
{ "command": { "action": "adjustFontSize", "delta": -1 }, "keys": "ctrl+-" },
{ "command": "resetFontSize", "keys": "ctrl+0" }
],
"commands": [
{ "icon": null, "name": { "key": "NewTabCommandKey" }, "action": "newTab" },
{ "icon": null, "name": { "key": "DuplicateTabCommandKey" }, "action": "duplicateTab" },
{ "icon": null, "name": { "key": "DuplicatePaneCommandKey" }, "action": { "action": "splitPane", "split":"auto", "splitMode": "duplicate" } },
{ "icon": null, "name": { "key": "SplitHorizontalCommandKey" }, "action": { "action": "splitPane", "split": "horizontal" } },
{ "icon": null, "name": { "key": "SplitVerticalCommandKey" }, "action": { "action": "splitPane", "split": "vertical" } },
{ "icon": null, "name": { "key": "CloseWindowCommandKey" }, "action": "closeWindow" },
{ "icon": null, "name": { "key": "ClosePaneCommandKey" }, "action": "closePane" },
{ "icon": null, "name": { "key": "OpenNewTabDropdownCommandKey" }, "action": "openNewTabDropdown" },
{ "icon": null, "name": { "key": "OpenSettingsCommandKey" }, "action": "openSettings" },
{ "icon": null, "name": { "key": "FindCommandKey" }, "action": "find" },
{ "icon": null, "name": { "key": "NextTabCommandKey" }, "action": "nextTab" },
{ "icon": null, "name": { "key": "PrevTabCommandKey" }, "action": "prevTab" },
{ "icon": null, "name": { "key": "ToggleFullscreenCommandKey" }, "action": "toggleFullscreen" },
{ "icon": null, "name": { "key": "CopyTextCommandKey" }, "action": { "action": "copy", "singleLine": false } },
{ "icon": null, "name": { "key": "PasteCommandKey" }, "action": "paste" },
{ "icon": null, "name": { "key": "IncreaseFontSizeCommandKey" }, "action": { "action": "adjustFontSize", "delta": 1 } },
{ "icon": null, "name": { "key": "DecreaseFontSizeCommandKey" }, "action": { "action": "adjustFontSize", "delta": -1 } },
{ "icon": null, "name": { "key": "ResetFontSizeCommandKey" }, "action": "resetFontSize" },
{ "icon": null, "name": { "key": "ScrollDownCommandKey" }, "action": "scrollDown" },
{ "icon": null, "name": { "key": "ScrollDownPageCommandKey" }, "action": "scrollDownPage" },
{ "icon": null, "name": { "key": "ScrollUpCommandKey" }, "action": "scrollUp" },
{ "icon": null, "name": { "key": "ScrollUpPageCommandKey" }, "action": "scrollUpPage" }
]
}

View File

@@ -63,6 +63,9 @@
<Page Include="../ColorPickupFlyout.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="../CommandPalette.xaml">
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<!-- ========================= Headers ======================== -->
<ItemGroup>
@@ -85,6 +88,12 @@
<ClInclude Include="../ColorPickupFlyout.h">
<DependentUpon>../ColorPickupFlyout.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="../CommandPalette.h">
<DependentUpon>../CommandPalette.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="../Command.h">
<DependentUpon>../Command.idl</DependentUpon>
</ClInclude>
<ClInclude Include="../Tab.h">
<DependentUpon>../Tab.idl</DependentUpon>
</ClInclude>
@@ -103,7 +112,7 @@
<ClInclude Include="../WslDistroGenerator.h" />
<ClInclude Include="../AzureCloudShellGenerator.h" />
<ClInclude Include="../TelnetGenerator.h" />
<ClInclude Include="..\ColorHelper.h" />
<ClInclude Include="../ColorHelper.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="../ShortcutActionDispatch.h">
<DependentUpon>../ShortcutActionDispatch.idl</DependentUpon>
@@ -146,6 +155,12 @@
<ClCompile Include="../ColorPickupFlyout.cpp">
<DependentUpon>../ColorPickupFlyout.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="../CommandPalette.cpp">
<DependentUpon>../CommandPalette.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="../Command.cpp">
<DependentUpon>../Command.idl</DependentUpon>
</ClCompile>
<ClCompile Include="../Tab.cpp">
<DependentUpon>../Tab.idl</DependentUpon>
</ClCompile>
@@ -166,6 +181,7 @@
<ClCompile Include="../Pane.LayoutSizeNode.cpp" />
<ClCompile Include="../ColorHelper.cpp" />
<ClCompile Include="../DebugTapConnection.cpp" />
<ClCompile Include="../CommandSerialization.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
@@ -229,7 +245,12 @@
<DependentUpon>../ColorPickupFlyout.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="../Tab.idl"/>
<Midl Include="../CommandPalette.idl">
<DependentUpon>../CommandPalette.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="../Command.idl" />
<Midl Include="../Tab.idl" />
</ItemGroup>
<!-- ========================= Misc Files ======================== -->
<ItemGroup>

View File

@@ -4,7 +4,7 @@
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="../Resources/en-US/Resources.resw" />
<PRIResource Include="..\Resources\en-US\Resources.resw" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="../init.cpp" />
@@ -59,7 +59,13 @@
<ClCompile Include="../Pane.LayoutSizeNode.cpp">
<Filter>pane</Filter>
</ClCompile>
<ClCompile Include="..\ColorHelper.cpp" />
<ClCompile Include="../AppCommandlineArgs.cpp" />
<ClCompile Include="../Commandline.cpp" />
<ClCompile Include="../ColorHelper.cpp" />
<ClCompile Include="../DebugTapConnection.cpp" />
<ClCompile Include="../CommandSerialization.cpp">
<Filter>settings</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="../Utils.h" />
@@ -107,8 +113,16 @@
<ClInclude Include="../Tab.h">
<Filter>tab</Filter>
</ClInclude>
<ClInclude Include="../TelnetGenerator.h" />
<ClInclude Include="..\ColorHelper.h" />
<ClInclude Include="../AppCommandlineArgs.h" />
<ClInclude Include="../Commandline.h" />
<ClInclude Include="../DebugTapConnection.h" />
<ClInclude Include="../ColorHelper.h" />
<ClInclude Include="../TelnetGenerator.h">
<Filter>profileGeneration</Filter>
</ClInclude>
<ClInclude Include="../CommandSerialization.h">
<Filter>settings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Midl Include="../AppLogic.idl">
@@ -126,6 +140,10 @@
<Midl Include="../Tab.idl">
<Filter>tab</Filter>
</Midl>
<Midl Include="../IF7Listener.idl" />
<Midl Include="../Command.idl">
<Filter>commandPalette</Filter>
</Midl>
</ItemGroup>
<ItemGroup>
<None Include="../packages.config" />
@@ -146,6 +164,9 @@
<Page Include="../ColorPickupFlyout.xaml">
<Filter>controls</Filter>
</Page>
<Page Include="../CommandPalette.xaml">
<Filter>commandPalette</Filter>
</Page>
</ItemGroup>
<ItemGroup>
<Filter Include="app">
@@ -169,6 +190,9 @@
<Filter Include="tab">
<UniqueIdentifier>{6d40e12f-b83f-462e-8f93-fa421f87b27e}</UniqueIdentifier>
</Filter>
<Filter Include="commandPalette">
<UniqueIdentifier>{2ad498e1-d8ea-4381-9464-a74c141bd7dd}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="..\App.xaml">

View File

@@ -28,6 +28,7 @@
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/windows.ui.core.h>
#include <winrt/Windows.ui.input.h>
#include <winrt/Windows.UI.Text.h>

View File

@@ -94,3 +94,11 @@ try
return loader.GetLocalizedString(key);
}
CATCH_FAIL_FAST()
bool HasLibraryResourceWithName(const std::wstring_view key)
try
{
static auto loader{ GetLibraryResourceLoader() };
return loader.HasResourceWithName(key);
}
CATCH_FAIL_FAST()

View File

@@ -68,3 +68,4 @@ namespace Microsoft::Console::Utils
__declspec(selectany) extern const wchar_t* g_WinRTUtilsLibraryResourceScope{ (x) };
winrt::hstring GetLibraryResourceString(const std::wstring_view key);
bool HasLibraryResourceWithName(const std::wstring_view key);

View File

@@ -107,15 +107,16 @@ public: \
private: \
type _##name{ __VA_ARGS__ };
// Use this macro to quickly implement both the getter and setter for an observable property.
// This is similar to the GETSET_PROPERTY macro above, except this will also raise a
// PropertyChanged event with the name of the property that has changed inside of the setter.
// Use this macro to quickly implement both the getter and setter for an
// observable property. This is similar to the GETSET_PROPERTY macro above,
// except this will also raise a PropertyChanged event with the name of the
// property that has changed inside of the setter. This also implements a
// private _setName() method, that the class can internally use to change the
// value when it _knows_ it doesn't need to raise the PropertyChanged event
// (like when the class is being initialized).
#define OBSERVABLE_GETSET_PROPERTY(type, name, event) \
public: \
type name() { return _##name; }; \
\
private: \
const type _##name; \
void name(const type& value) \
{ \
if (_##name != value) \
@@ -123,6 +124,13 @@ private:
const_cast<type&>(_##name) = value; \
event(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L#name }); \
} \
}; \
\
private: \
const type _##name; \
void _set##name(const type& value) \
{ \
const_cast<type&>(_##name) = value; \
};
// Use this macro for quickly defining the factory_implementation part of a