This commit is contained in:
Pankaj Bhojwani 2025-08-12 15:45:34 -07:00
commit 9eb6c7746c
422 changed files with 10149 additions and 5917 deletions

View File

@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"XamlStyler.Console": {
"version": "3.2311.2",
"version": "3.2501.8",
"commands": [
"xstyler"
]

View File

@ -11,34 +11,25 @@ colorbrewer
commandlines
consvc
copyable
CText
dalet
dcs
deselection
dialytika
diffing
Dimidium
dje
downsides
dze
dzhe
Emacspeak
Fitt
FTCS
flac
FTCS
gantt
gfm
ghe
gje
godbolt
hstrings
hyperlinking
hyperlinks
Kbds
kje
libfuzzer
liga
lje
Llast
Lmid
locl
@ -50,10 +41,8 @@ minimalistic
mkmk
mnt
mru
nje
notwrapped
NTMTo
ogonek
overlined
perlw
postmodern
@ -61,8 +50,8 @@ Powerline
ptys
pwn
pwshw
QOL
qof
QOL
qps
quickfix
rclt
@ -75,17 +64,13 @@ rlig
rubyw
runtimes
servicebus
shcha
similaritytolerance
slnt
stakeholders
subpage
sustainability
sxn
TLDR
tonos
Tencent
toolset
tshe
UEFI
uiatextrange
und
@ -93,8 +78,5 @@ vsdevcmd
westus
workarounds
WSLs
wtconfig
XBox
YBox
yeru
zhe

View File

@ -2,11 +2,8 @@ aalt
abvm
ACCEPTFILES
ACCESSDENIED
acl
aclapi
alignas
alignof
allocconsolewithoptions
APPLYTOSUBMENUS
appxrecipe
bitfield
@ -15,29 +12,20 @@ BUILDBRANCH
BUILDMSG
BUILDNUMBER
BYCOMMAND
BYPOSITION
charconv
CLASSNOTAVAILABLE
CLOSEAPP
cmdletbinding
COLORPROPERTY
colspan
COMDLG
commandlinetoargv
commoncontrols
comparand
COPYFROMRESOURCE
cstdint
CXICON
CYICON
Dacl
dataobject
dcomp
debugbreak
delayimp
DERR
dlldata
DNE
dnom
DONTADDTORECENT
DWMSBT
@ -64,81 +52,42 @@ GETHIGHCONTRAST
GETMOUSEHOVERTIME
GETTEXTLENGTH
HARDBREAKS
Hashtable
HIGHCONTRASTON
HIGHCONTRASTW
HIGHQUALITYSCALE
hinternet
HINTERNET
hotkeys
href
hrgn
HTCLOSE
hwinsta
HWINSTA
IActivation
IApp
IAppearance
IAsync
IBind
IBox
IClass
IComparable
IComparer
ICONINFO
IConnection
ICustom
IDialog
IDirect
Idn
IExplorer
IFACEMETHOD
IFile
IGraphics
IImage
IInheritable
IMap
imm
IObject
iosfwd
IPackage
isa
ISetup
isspace
IStorage
istream
IStringable
ITab
ITaskbar
itow
IUri
IVirtual
KEYSELECT
LCID
LINEBREAK
llabs
llu
localtime
lround
Lsa
lsass
LSHIFT
LTGRAY
MAINWINDOW
MAXIMIZEBOX
medi
memchr
memicmp
MENUCOMMAND
MENUDATA
MENUINFO
MENUITEMINFOW
MINIMIZEBOX
mmeapi
MOUSELEAVE
mov
mptt
msappx
MULTIPLEUSE
NCHITTEST
NCLBUTTONDBLCLK
@ -148,7 +97,6 @@ NCPOINTERUPDATE
NCRBUTTONDBLCLK
NIF
NIN
NOAGGREGATION
NOASYNC
NOBREAKS
NOCHANGEDIR
@ -161,8 +109,6 @@ NOTIFYICONDATA
ntprivapi
NTSYSCALLAPI
numr
oaidl
ocidl
ODR
offsetof
ofstream
@ -172,22 +118,17 @@ OSVERSIONINFOEXW
otms
OUTLINETEXTMETRICW
overridable
PACL
PAGESCROLL
PALLOC
PATINVERT
PEXPLICIT
PICKFOLDERS
PINPUT
pmr
ptstr
QUERYENDSESSION
rcx
REGCLS
RETURNCMD
rfind
RLO
rnrn
ROOTOWNER
roundf
RSHIFT
@ -206,22 +147,17 @@ SHOWTIP
SINGLEUSE
SIZENS
smoothstep
snprintf
SOFTBREAK
spsc
sregex
SRWLOC
srwlock
SRWLOCK
STDCPP
STDMETHOD
strchr
strcpy
streambuf
strtoul
Stubless
Subheader
Subpage
syscall
syscolors
SYSTEMBACKDROP
@ -238,23 +174,18 @@ tokeninfo
tolower
toupper
TRACKMOUSEEVENT
TTask
TVal
ubrk
UChar
UFIELD
ULARGE
UOI
UPDATEINIFILE
urlmon
userenv
USEROBJECTFLAGS
Vcpp
Viewbox
virtualalloc
vsnwprintf
wcsnlen
wcsstr
wcstoui
WDJ
winhttp
wininet
@ -264,10 +195,8 @@ winstamin
wmemcmp
wpc
WSF
wsregex
WWH
wwinmain
xchg
XDocument
XElement
xfacet

View File

@ -1,5 +1,4 @@
CHINESEBIG
choseong
Jongseong
Jungseong
ssangtikeut
Choseong
CHOSEONG

View File

@ -1,4 +1,3 @@
alice
aliceblue
antiquewhite
blanchedalmond
@ -39,7 +38,6 @@ gainsboro
ghostwhite
greenyellow
hotpink
indian
indianred
lavenderblush
lawngreen
@ -74,7 +72,6 @@ mediumvioletred
midnightblue
mintcream
mistyrose
navajo
navajowhite
navyblue
oldlace
@ -88,7 +85,6 @@ papayawhip
peachpuff
peru
powderblue
rebecca
rebeccapurple
rosybrown
royalblue
@ -109,9 +105,4 @@ webgrey
webmaroon
webpurple
whitesmoke
xaroon
xray
xreen
xrey
xurple
yellowgreen

View File

@ -1,8 +1,8 @@
Consolas
emoji
emojis
Emojis
Extralight
Gabriola
Iosevka
MDL
Monofur

View File

@ -1,4 +1 @@
arigatoo
doomo
Kaomojis
TATEGAKI

View File

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

View File

@ -4,12 +4,11 @@ advapi
akv
AKV
altform
altforms
Altforms
appendwttlogging
appinstaller
appx
appxbundle
appxerror
appxmanifest
ATL
autoexec
@ -25,66 +24,44 @@ CPRs
cryptbase
cscript
DACL
DACLs
defaultlib
diffs
disposables
dotnetfeed
DTDs
DWINRT
enablewttlogging
HOMESHARE
Intelli
issecret
IVisual
libucrt
libucrtd
LKG
LOCKFILE
LTCG
Lxss
makepri
mfcribbon
microsoft
microsoftonline
MSAA
msixbundle
MSVC
MSVCP
mtu
muxc
netcore
Onefuzz
osgvsowi
PFILETIME
pgc
pgo
pgosweep
powerrename
powershell
priconfig
PRIINFO
propkey
pscustomobject
QWORD
rdpclip
regedit
resfiles
robocopy
SACLs
sdkddkver
segoe
Shobjidl
sid
Skype
SRW
sxs
symbolrequestprod
Sysinternals
sysnative
systemroot
taskkill
tasklist
tdbuildteamid
ucrt
ucrtd
unvirtualized
@ -92,12 +69,9 @@ USERDNSDOMAIN
VCRT
vcruntime
Virtualization
visualstudio
vscode
VSTHRD
WINBASEAPI
winsdkver
wlk
wscript
wslpath
wtl

View File

@ -1,4 +1,3 @@
Anup
arkthur
austdi
Ballmer
@ -6,13 +5,11 @@ bhoj
Bhojwani
Bluloco
carlos
craigloewen
dhowett
Diviness
dsafa
duhowett
DXP
ekg
eryksun
ethanschoonover
Firefox
@ -25,70 +22,43 @@ Hernan
Howett
Illhardt
Imms
iquilezles
italo
jantari
jerrysh
Kaiyu
kimwalisch
KMehrain
Kodelife
KODELIFE
Kourosh
kowalczyk
leonardder
leonmsft
Lepilleur
lhecker
lukesampson
Macbook
Manandhar
Lovecraft
masserano
mbadolato
Mehrain
menger
mgravell
michaelniksa
michkap
migrie
mikegr
mikemaccana
miloush
miniksa
nguyen
niksa
nvaccess
nvda
oising
oldnewthing
opengl
osgwiki
Ottosson
pabhojwa
panos
Panos
paulcam
pauldotknopf
PGP
Pham
Rincewind
rprichard
Schoonover
shadertoy
Shomnipotence
simioni
Somuah
sonph
sonpham
stakx
talo
thereses
Thysell
Walisch
WDX
Wellons
Westerman
Wirt
Wojciech
zadjii
Zamor
zamora
@ -96,4 +66,3 @@ Zamora
zljubisic
Zoey
zorio
Zverovich

View File

@ -1,3 +1,6 @@
# Repeated letters
\b([a-z])\g{-1}{2,}\b
# marker to ignore all code on line
^.*/\* #no-spell-check-line \*/.*$
# marker to ignore all code on line
@ -7,6 +10,9 @@
# cspell inline
^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b
# copyright
Copyright (?:\([Cc]\)|)(?:[-\d, ]|and)+(?: [A-Z][a-z]+ [A-Z][a-z]+,?)+
# patch hunk comments
^@@ -\d+(?:,\d+|) \+\d+(?:,\d+|) @@ .*
# git index header
@ -15,6 +21,9 @@ index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# file permissions
['"`\s][-bcdLlpsw](?:[-r][-w][-Ssx]){2}[-r][-w][-SsTtx]\+?['"`\s]
# css fonts
\bfont(?:-family|):[^;}]+
# css url wrappings
\burl\([^)]+\)
@ -32,9 +41,6 @@ index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40}
# https/http/file urls
(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/*%?=~_|!:,.;]+[-A-Za-z0-9+&@#/*%=~_|]
# https/http/file urls
(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@._]{3,}
@ -69,6 +75,8 @@ magnet:[?=:\w]+
# Amazon
\bamazon\.com/[-\w]+/(?:dp/[0-9A-Z]+|)
# AWS ARN
arn:aws:[-/:\w]+
# AWS S3
\b\w*\.s3[^.]*\.amazonaws\.com/[-\w/&#%_?:=]*
# AWS execute-api
@ -95,6 +103,8 @@ vpc-\w+
\bgoogle-analytics\.com/collect.[-0-9a-zA-Z?%=&_.~]*
# Google APIs
\bgoogleapis\.(?:com|dev)/[a-z]+/(?:v\d+/|)[a-z]+/[-@:./?=\w+|&]+
# Google Artifact Registry
\.pkg\.dev(?:/[-\w]+)+(?::[-\w]+|)
# Google Storage
\b[-a-zA-Z0-9.]*\bstorage\d*\.googleapis\.com(?:/\S*|)
# Google Calendar
@ -130,6 +140,8 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+.
\bscholar\.google\.com/citations\?user=[A-Za-z0-9_]+
# Google Colab Research Drive
\bcolab\.research\.google\.com/drive/[-0-9a-zA-Z_?=]*
# Google Cloud regions
(?:us|(?:north|south)america|europe|asia|australia|me|africa)-(?:north|south|east|west|central){1,2}\d+
# GitHub SHAs (api)
\bapi.github\.com/repos(?:/[^/\s"]+){3}/[0-9a-f]+\b
@ -168,6 +180,12 @@ GHSA(?:-[0-9a-z]{4}){3}
# GitLab commits
\bgitlab\.[^/\s"]*/(?:[^/\s"]+/){2}commits?/[0-9a-f]+\b
# #includes
^\s*#include\s*(?:<.*?>|".*?")
# #pragma lib
^\s*#pragma comment\(lib, ".*?"\)
# binance
accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
@ -220,7 +238,7 @@ accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]*
\bmedium\.com/@?[^/\s"]+/[-\w]+
# microsoft
\b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]*
\b(?:https?://|)(?:(?:(?:blogs|download\.visualstudio|docs|msdn2?|research)\.|)microsoft|blogs\.msdn)\.co(?:m|\.\w\w)/[-_a-zA-Z0-9()=./%]*
# powerbi
\bapp\.powerbi\.com/reportEmbed/[^"' ]*
# vs devops
@ -394,7 +412,7 @@ ipfs://[0-9a-zA-Z]{3,}
\bgetopts\s+(?:"[^"]+"|'[^']+')
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m
(?:\\(?:u00|x)1[Bb]|\\03[1-7]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+)*m
# URL escaped characters
%[0-9A-F][A-F](?=[A-Za-z])
@ -431,10 +449,14 @@ sha\d+:[0-9a-f]*?[a-f]{3,}[0-9a-f]*
# pki (base64)
LS0tLS1CRUdJT.*
# C# includes
^\s*using [^;]+;
# 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}|[iu]\d+)\b
(?:[\\0][xX]|\\u|[uU]\+|#x?|%23|&H)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
# integrity
integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1}
@ -452,7 +474,10 @@ integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1}
Name\[[^\]]+\]=.*
# IServiceProvider / isAThing
(?:\b|_)(?:(?:ns|)I|isA)(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
(?:(?:\b|_|(?<=[a-z]))I|(?:\b|_)(?:nsI|isA))(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
# python
\b(?i)py(?!gments|gmy|lon|ramid|ro|th)(?=[a-z]{2,})
# crypt
(['"])\$2[ayb]\$.{56}\g{-1}
@ -466,17 +491,14 @@ Name\[[^\]]+\]=.*
# machine learning (?)
\b(?i)ml(?=[a-z]{2,})
# python
\b(?i)py(?!gments|gmy|lon|ramid|ro|th)(?=[a-z]{2,})
# scrypt / argon
\$(?:scrypt|argon\d+[di]*)\$\S+
# go.sum
\bh1:\S+
# scala imports
^import (?:[\w.]|\{\w*?(?:,\s*(?:\w*|\*))+\})+
# imports
^import\s+(?:(?:static|type)\s+|)(?:[\w.]|\{\s*\w*?(?:,\s*(?:\w*|\*))+\s*\})+
# scala modules
("[^"]+"\s*%%?\s*){2,3}"[^"]+"
@ -485,7 +507,7 @@ Name\[[^\]]+\]=.*
image: [-\w./:@]+
# Docker images
^\s*FROM\s+\S+:\S+(?:\s+AS\s+\S+|)
^\s*(?i)FROM\s+\S+:\S+(?:\s+AS\s+\S+|)
# `docker images` REPOSITORY TAG IMAGE ID CREATED SIZE
\s*\S+/\S+\s+\S+\s+[0-9a-f]{8,}\s+\d+\s+(?:hour|day|week)s ago\s+[\d.]+[KMGT]B
@ -501,6 +523,7 @@ content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
# The `(?=.*?")` suffix should limit the false positives rate
# printf
#%(?:(?:(?:hh?|ll?|[jzt])?[diuoxn]|l?[cs]|L?[fega]|p)(?=[a-z]{2,})|(?:X|L?[FEGA])(?=[a-zA-Z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%)\b)(?=.*?['"])
# Alternative printf
# %s
%(?:s(?=[a-z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%[^s])\b)(?=.*?['"])
@ -524,7 +547,7 @@ content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1}
# javascript replace regex
\.replace\(/[^/\s"]{3,}/[gim]*\s*,
# assign regex
= /[^*].*?(?:[a-z]{3,}|[A-Z]{3,}|[A-Z][a-z]{2,}).*/[gi]?(?=\W|$)
= /[^*].*?(?:[a-z]{3,}|[A-Z]{3,}|[A-Z][a-z]{2,}).*/[gim]*(?=\W|$)
# perl regex test
[!=]~ (?:/.*/|m\{.*?\}|m<.*?>|m([|!/@#,;']).*?\g{-1})
@ -538,7 +561,7 @@ perl(?:\s+-[a-zA-Z]\w*)+
(?:\d|\bh)to(?!ken)(?=[a-z])|to(?=[adhiklpun]\()
# Go regular expressions
regexp?\.MustCompile\(`[^`]*`\)
regexp?\.MustCompile\((?:`[^`]*`|".*"|'.*')\)
# regex choice
\(\?:[^)]+\|[^)]+\)
@ -586,7 +609,7 @@ urn:shemas-jetbrains-com
# xcode
# xcodeproject scenes
(?:Controller|destination|ID|id)="\w{3}-\w{2}-\w{3}"
(?:Controller|destination|(?:first|second)Item|ID|id)="\w{3}-\w{2}-\w{3}"
# xcode api botches
customObjectInstantitationMethod
@ -601,14 +624,17 @@ PrependWithABINamepsace
\.fa-[-a-z0-9]+
# bearer auth
(['"])[Bb]ear[e][r] .*?\g{-1}
(['"])[Bb]ear[e][r] .{3,}?\g{-1}
# bearer auth
\b[Bb]ear[e][r]:? [-a-zA-Z=;:/0-9+.]+
\b[Bb]ear[e][r]:? [-a-zA-Z=;:/0-9+.]{3,}
# basic auth
(['"])[Bb]asic [-a-zA-Z=;:/0-9+]{3,}\g{-1}
# basic auth
: [Bb]asic [-a-zA-Z=;:/0-9+.]{3,}
# base64 encoded content
#([`'"])[-a-zA-Z=;:/0-9+]{3,}=\g{-1}
# base64 encoded content in xml/sgml
@ -620,6 +646,9 @@ PrependWithABINamepsace
# base64 encoded pkcs
#\bMII[-a-zA-Z=;:/0-9+]+
# uuencoded
#[!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_]{40,}
# DNS rr data
#(?:\d+\s+){3}(?:[-+/=.\w]{2,}\s*){1,2}
@ -630,7 +659,7 @@ PrependWithABINamepsace
\bnumer\b(?=.*denom)
# Time Zones
\b(?:Africa|Atlantic|America|Antarctica|Asia|Australia|Europe|Indian|Pacific)(?:/\w+)+
\b(?:Africa|Atlantic|America|Antarctica|Arctic|Asia|Australia|Europe|Indian|Pacific)(?:/[-\w]+)+
# linux kernel info
^(?:bugs|flags|Features)\s+:.*
@ -676,11 +705,17 @@ TeX/AMS
"varsIgnorePattern": ".+"
# nolint
nolint:\w+
nolint:\s*[\w,]+
# Windows short paths
[/\\][^/\\]{5,6}~\d{1,2}(?=[/\\])
# Windows Resources with accelerators
\b[A-Z]&[a-z]+\b(?!;)
# signed off by
(?i)Signed-off-by: .*
# cygwin paths
/cygdrive/[a-zA-Z]/(?:Program Files(?: \(.*?\)| ?)(?:/[-+.~\\/()\w ]+)*|[-+.~\\/()\w])+
@ -715,29 +750,29 @@ W/"[^"]+"
# Compiler flags (Unix, Java/Scala)
# Use if you have things like `-Pdocker` and want to treat them as `docker`
#(?:^|[\t ,>"'`=(])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
#(?:^|[\t ,>"'`=(#])-(?:(?:J-|)[DPWXY]|[Llf])(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# Compiler flags (Windows / PowerShell)
# This is a subset of the more general compiler flags pattern.
# It avoids matching `-Path` to prevent it from being treated as `ath`
#(?:^|[\t ,"'`=(])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
#(?:^|[\t ,"'`=(#])-(?:[DPL](?=[A-Z]{2,})|[WXYlf](?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}))
# Compiler flags (linker)
,-B
# libraries
#(?:\b|_)lib(?:re(?=office)|)(?!era[lt]|ero|erty|rar(?:i(?:an|es)|y))(?=[a-z])
# WWNN/WWPN (NAA identifiers)
\b(?:0x)?10[0-9a-f]{14}\b|\b(?:0x|3)?[25][0-9a-f]{15}\b|\b(?:0x|3)?6[0-9a-f]{31}\b
#(?:\b|_)[Ll]ib(?:re(?=office)|)(?!era[lt]|ero|erty|rar(?:i(?:an|es)|y))(?=[a-z])
# iSCSI iqn (approximate regex)
\biqn\.[0-9]{4}-[0-9]{2}(?:[\.-][a-z][a-z0-9]*)*\b
# WWNN/WWPN (NAA identifiers)
\b(?:0x)?10[0-9a-f]{14}\b|\b(?:0x|3)?[25][0-9a-f]{15}\b|\b(?:0x|3)?6[0-9a-f]{31}\b
# curl arguments
\b(?:\\n|)curl(?:\.exe|)(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# set arguments
\b(?:bash|sh|set)(?:\s+-[abefimouxE]{1,2})*\s+-[abefimouxE]{3,}(?:\s+-[abefimouxE]+)*
\b(?:bash|sh|set)(?:\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...

View File

@ -97,7 +97,7 @@ Resources/(?!en)
^doc/reference/UTF8-torture-test\.txt$
^doc/reference/windows-terminal-logo\.ans$
^NOTICE.md
^oss/
^oss/.*?/
^samples/PixelShaders/Screenshots/
^src/cascadia/TerminalSettingsEditor/SegoeFluentIconList.h$
^src/interactivity/onecore/BgfxEngine\.
@ -121,8 +121,8 @@ Resources/(?!en)
^tools/ReleaseEngineering/ServicingPipeline\.ps1$
^XamlStyler\.json$
^\.github/actions/spelling/
^\.github/workflows/spelling\d*\.yml$
^\.vsconfig$
^\Q.github/workflows/spelling.yml\E$
^\Qbuild/config/release.gdnbaselines\E$
^\Qdep/WinAppDriver/EULA.rtf\E$
^\Qdoc/reference/windows-terminal-logo.ans\E$
@ -133,3 +133,4 @@ Resources/(?!en)
^\Qsrc/terminal/parser/ft_fuzzwrapper/run.bat\E$
^\Qsrc/tools/lnkd/lnkd.bat\E$
^\Qsrc/tools/pixels/pixels.bat\E$
^\Qsrc/cascadia/ut_app/FzfTests.cpp\E$

View File

@ -1,38 +1,19 @@
AAAAAABBBBBBCCC
AAAAABBBBBBCCC
abcd
ABCDEFGHIJ
abcdefghijk
ABCDEFGHIJKLMNOPQRS
ABCDEFGHIJKLMNOPQRST
ABCDEFGHIJKLMNOPQRSTUVWXY
ABCG
ABE
abf
BBBBB
BBBBBCCC
BBBBCCCCC
AZZ
BBDM
BBGGRR
EFG
CBN
cbt
Ccc
cch
efg
EFGh
efgh
KLMNOQQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJ
QQQQQQQQQQABCDEFGHIJKLMNOPQRS
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJKLMNOPQRSTQQQQQQQQQQ
QQQQQQQQQQABCDEFGHIJPQRST
QQQQQQQQQQABCDEFGHIJPQRSTQQQQQQQQQQ
fdw
fesb
ffd
FFFD
qwerty
qwertyuiopasdfg
ZAAZZ
ZABBZ
ZBAZZ
ZBBBZ
ZBBZZ
ZYXWVUT
ZZBBZ
ZZZBB
ZZZBZ
ZZZZZ
zzf

View File

@ -2,7 +2,7 @@ aaaaabbb
aabbcc
ABANDONFONT
abbcc
ABCF
abcc
abgr
ABORTIFHUNG
ACCESSTOKEN
@ -26,13 +26,11 @@ AImpl
AInplace
ALIGNRIGHT
allocing
allocs
alpc
ALTERNATENAME
ALTF
ALTNUMPAD
ALWAYSTIP
aml
ansicpg
ANSISYS
ANSISYSRC
@ -49,22 +47,17 @@ APIENTRY
apiset
APPBARDATA
appcontainer
appium
appletname
applicationmodel
APPLMODAL
Applocal
appmodel
appshellintegration
APPWINDOW
APPXMANIFESTVERSION
APrep
apsect
APSTUDIO
archeologists
Argb
ARRAYSIZE
ARROWKEYS
asan
ASBSET
ASetting
ASingle
@ -72,11 +65,11 @@ ASYNCDONTCARE
ASYNCWINDOWPOS
atch
ATest
atg
aumid
Authenticode
AUTOBUDDY
AUTOCHECKBOX
autocrlf
autohide
AUTOHSCROLL
automagically
@ -86,16 +79,13 @@ autoscrolling
Autowrap
AVerify
awch
AZCOPY
azurecr
AZZ
backgrounded
Backgrounder
backgrounding
backported
backstory
Bazz
bbb
bbccb
BBDM
bbwe
@ -123,13 +113,13 @@ bitmasks
BITOPERATION
BKCOLOR
BKGND
BKMK
Bksp
Blt
blu
BLUESCROLL
bmi
bodgy
BODGY
BOLDFONT
Borland
boutput
@ -148,9 +138,7 @@ buflen
buildsystems
buildtransitive
BValue
bytebuffer
cac
cacafire
Cacafire
CALLCONV
CANDRABINDU
capslock
@ -161,12 +149,6 @@ catid
cazamor
CBash
cbiex
CBN
cbt
Ccc
CCCBB
CCCDDD
cch
CCHAR
CCmd
ccolor
@ -181,15 +163,14 @@ cfie
cfiex
cfte
CFuzz
cgmanifest
cgscrn
chafa
changelists
CHARSETINFO
chh
chshdng
CHT
CLASSSTRING
CLE
cleartype
CLICKACTIVE
clickdown
@ -212,9 +193,7 @@ cmw
CNL
cnn
Codeflow
codenav
codepages
codepath
coinit
colorizing
COLORONCOLOR
@ -226,13 +205,8 @@ colortbl
colortest
colortool
COLORVALUE
combaseapi
comctl
commandline
commctrl
commdlg
COMMITID
componentization
conapi
conattrs
conbufferout
@ -250,7 +224,6 @@ conintegrityuwp
coninteractivitybase
coninteractivityonecore
coninteractivitywin
conio
coniosrv
CONKBD
conlibk
@ -263,13 +236,13 @@ conpropsp
conpty
conptylib
conserv
consoleaccessibility
consoleapi
CONSOLECONTROL
CONSOLEENDTASK
consolegit
consolehost
CONSOLEIME
consoleinternal
CONSOLESETFOREGROUND
consoletaeftemplates
consoleuwp
@ -277,7 +250,6 @@ Consolewait
CONSOLEWINDOWOWNER
consrv
constexprable
constness
contentfiles
conterm
contsf
@ -311,7 +283,6 @@ csbi
csbiex
CSHORT
Cspace
csrmsg
CSRSS
csrutil
CSTYLE
@ -368,16 +339,14 @@ DBGFONTS
DBGOUTPUT
dbh
dblclk
DBUILD
Dcd
DColor
dcommon
DCOMMON
DComposition
DDDCCC
dde
DDESHARE
DDevice
DEADCHAR
dealloc
Debian
debugtype
DECAC
@ -482,18 +451,16 @@ DELAYLOAD
DELETEONRELEASE
depersist
deprioritized
deserializers
desktopwindowxamlsource
devicecode
Dext
DFactory
DFF
dialogbox
DINLINE
directio
DIRECTX
DISABLEDELAYEDEXPANSION
DISABLENOSCROLL
DISPATCHNOTIFY
DISPLAYATTRIBUTE
DISPLAYCHANGE
distros
@ -530,9 +497,10 @@ dsm
dsound
DSSCL
DSwap
DTest
DTo
DTTERM
DUNICODE
DUNIT
dup'ed
dvi
dwl
@ -542,8 +510,6 @@ dwmapi
DWORDs
dwrite
dxgi
dxgidwm
dxinterop
dxsm
dxttbmp
Dyreen
@ -557,7 +523,6 @@ EDITKEYS
EDITTEXT
EDITUPDATE
Efast
efghijklmn
EHsc
EINS
ELEMENTNOTAVAILABLE
@ -566,7 +531,6 @@ enabledelayedexpansion
ENDCAP
endptr
ENTIREBUFFER
entrypoints
ENU
ENUMLOGFONT
ENUMLOGFONTEX
@ -581,7 +545,6 @@ esrp
ESV
ETW
EUDC
EVENTID
eventing
evflags
evt
@ -603,16 +566,6 @@ FACESIZE
FAILIFTHERE
fastlink
fcharset
FDEA
fdw
FECF
FEEF
fesb
FFAF
ffd
FFDE
FFFD
FFFDb
fgbg
FGCOLOR
FGHIJ
@ -630,7 +583,6 @@ FINDDLG
FINDDOWN
FINDREGEX
FINDSTRINGEXACT
FINDUP
FITZPATRICK
FIXEDFILEINFO
Flg
@ -651,6 +603,7 @@ FONTSTRING
FONTTYPE
FONTWIDTH
FONTWINDOW
foob
FORCEOFFFEEDBACK
FORCEONFEEDBACK
FRAMECHANGED
@ -664,13 +617,14 @@ Ftm
Fullscreens
Fullwidth
FUNCTIONCALL
fuzzer
fuzzmain
fuzzmap
fuzzwrapper
fuzzyfinder
fwdecl
fwe
fwlink
fzf
gci
gcx
gdi
@ -726,6 +680,7 @@ GETWHEELSCROLLCHARS
GETWHEELSCROLLLINES
Gfun
gfx
gfycat
GGI
GHgh
GHIJK
@ -746,6 +701,7 @@ Greyscale
gridline
gset
gsl
Guake
guc
GUIDATOM
GValue
@ -775,7 +731,6 @@ hfind
hfont
hfontresource
hglobal
hhh
hhook
hhx
HIBYTE
@ -791,7 +746,6 @@ HKCU
hkey
hkl
HKLM
hlocal
hlsl
HMB
HMK
@ -810,7 +764,6 @@ HREDRAW
hresult
hscroll
hstr
hstring
HTBOTTOMLEFT
HTBOTTOMRIGHT
HTCAPTION
@ -839,14 +792,12 @@ idl
idllib
IDOK
IDR
idth
IDTo
IDXGI
IFACEMETHODIMP
ification
IGNORELANGUAGE
iid
IInput
IIo
ILC
ILCo
@ -860,20 +811,18 @@ INFOEX
inheritcursor
INITCOMMONCONTROLSEX
INITDIALOG
initguid
INITGUID
INITMENU
inkscape
INLINEPREFIX
inproc
Inputkeyinfo
inputpaneinterop
Inputreadhandledata
INPUTSCOPE
INSERTMODE
INTERACTIVITYBASE
INTERCEPTCOPYPASTE
INTERNALNAME
Interner
intsafe
INVALIDARG
INVALIDATERECT
@ -885,8 +834,6 @@ itermcolors
itf
Ith
IUI
IUnknown
ivalid
IWIC
IXP
jconcpp
@ -910,7 +857,6 @@ keydowns
KEYFIRST
KEYLAST
Keymapping
keyscan
keystate
keyups
Kickstart
@ -920,10 +866,6 @@ kinda
KIYEOK
KLF
KLMNO
KLMNOPQRST
KLMNOPQRSTQQQQQ
KLMNOPQRSTUVWXY
KLMNOPQRSTY
KOK
KPRIORITY
KVM
@ -945,6 +887,8 @@ LCONTROL
LCTRL
lcx
LEFTALIGN
libsancov
libtickit
LIMITTEXT
LINEDOWN
LINESELECTION
@ -1049,6 +993,7 @@ MBUTTONDOWN
MBUTTONUP
mdmerge
MDs
mdtauk
MEASUREITEM
megamix
memallocator
@ -1058,7 +1003,6 @@ MENUCONTROL
MENUDROPALIGNMENT
MENUITEMINFO
MENUSELECT
messageext
metaproj
Mgrs
microsoftpublicsymbols
@ -1075,11 +1019,9 @@ minwindef
MMBB
mmcc
MMCPL
mmsystem
MNC
MNOPQ
MNOPQR
MNOPQRSTUVWXY
MODALFRAME
MODERNCORE
MONITORINFO
@ -1091,7 +1033,6 @@ MOUSEHWHEEL
MOVESTART
msb
msbuildcache
msctf
msctls
msdata
MSDL
@ -1106,10 +1047,9 @@ MSGSELECTMODE
msiexec
MSIL
msix
msrc
MSRC
MSVCRTD
MTSM
Munged
murmurhash
muxes
myapplet
@ -1148,7 +1088,6 @@ Newtonsoft
NEXTLINE
nfe
NLSMODE
nnn
NOACTIVATE
NOAPPLYNOW
NOCLIP
@ -1201,40 +1140,31 @@ NPFS
nrcs
NSTATUS
ntapi
ntcon
ntcsrdll
ntdef
NTDEV
ntdll
ntifs
ntlpcapi
ntm
ntrtl
ntstatus
nttree
nturtl
ntuser
NTVDM
ntverp
nugetversions
NUKTA
nullness
nullonfailure
nullopts
numlock
NUMSCROLL
NUnit
nupkg
NVIDIA
NVT
OACR
objbase
ocolor
oemcp
OEMFONT
OEMFORMAT
OEMs
offboarded
OLEAUT
OLECHAR
onebranch
@ -1248,6 +1178,7 @@ onecoreuuid
ONECOREWINDOWS
onehalf
oneseq
oob
openbash
opencode
opencon
@ -1283,7 +1214,6 @@ PALPC
pankaj
parentable
PATCOPY
pathcch
PATTERNID
pbstr
pcb
@ -1338,7 +1268,6 @@ phicon
phwnd
pidl
PIDLIST
pids
pii
piml
pimpl
@ -1363,11 +1292,9 @@ POINTERUPDATE
POINTSLIST
policheck
POLYTEXTW
poppack
POPUPATTR
popups
PORFLG
positionals
POSTCHARBREAKS
POSX
POSXSCROLL
@ -1400,11 +1327,9 @@ PREVLINE
prg
pri
prioritization
processenv
processhost
PROCESSINFOCLASS
PRODEXT
Productize
PROPERTYID
PROPERTYKEY
propertyval
@ -1416,16 +1341,12 @@ propsys
PROPTITLE
propvar
propvariant
propvarutil
psa
PSCRED
PSECURITY
pseudoconsole
pseudoterminal
psh
pshn
PSHNOTIFY
pshpack
PSINGLE
psl
psldl
@ -1497,8 +1418,6 @@ REGISTERVDM
regkey
REGSTR
RELBINPATH
remoting
renamer
rendersize
reparented
reparenting
@ -1533,19 +1452,16 @@ RIGHTALIGN
RIGHTBUTTON
riid
ris
roadmap
robomac
rodata
rosetta
RRF
rrr
RRRGGGBB
rsas
rtcore
RTEXT
RTLREADING
Rtn
ruleset
runas
RUNDLL
runformat
@ -1563,7 +1479,6 @@ rvpa
RWIN
rxvt
safemath
sancov
sba
SBCS
SBCSDBCS
@ -1591,10 +1506,8 @@ SCROLLSCREENBUFFER
scursor
sddl
SDKDDK
securityappcontainer
segfault
SELCHANGE
SELECTALL
SELECTEDFONT
SELECTSTRING
Selfhosters
@ -1638,14 +1551,10 @@ SFUI
sgr
SHCo
shcore
shellapi
shellex
shellscalingapi
SHFILEINFO
SHGFI
SHIFTJIS
shlguid
shlobj
shlwapi
SHORTPATH
SHOWCURSOR
@ -1683,7 +1592,6 @@ snapcy
snk
SOLIDBOX
Solutiondir
somefile
sourced
SRCAND
SRCCODEPAGE
@ -1715,9 +1623,8 @@ STDEXT
STDMETHODCALLTYPE
STDMETHODIMP
STGM
Stringable
STRINGTABLE
strsafe
STRSAFE
STUBHEAD
STUVWX
stylecop
@ -1743,32 +1650,27 @@ SYSLIB
SYSLINK
SYSMENU
sysparams
sysparamsext
SYSTEMHAND
SYSTEMMENU
SYSTEMTIME
tabview
TAdd
taef
TARG
targetentrypoint
TARGETLIBS
TARGETNAME
targetver
TBase
tbc
tbi
Tbl
TBM
tchar
TCHAR
TCHFORMAT
TCI
tcommands
tdbuild
Tdd
TDelegated
TDP
tearoff
Teb
Techo
tellp
@ -1778,7 +1680,6 @@ terminalinput
terminalrenderdata
TERMINALSCROLLING
terminfo
TEs
testcon
testd
testenvs
@ -1790,7 +1691,6 @@ TESTNULL
testpass
testpasses
TEXCOORD
TExpected
textattribute
TEXTATTRIBUTEID
textboxes
@ -1801,39 +1701,28 @@ TEXTMETRIC
TEXTMETRICW
textmode
texttests
TFunction
THUMBPOSITION
THUMBTRACK
tickit
TIcon
tilunittests
titlebars
TITLEISLINKNAME
TJson
TLambda
TLDP
TLEN
TMAE
TMPF
TMult
tmultiple
TODOs
tofrom
tokenhelpers
toolbars
TOOLINFO
TOOLWINDOW
TOPDOWNDIB
TOpt
tosign
touchpad
tracelogging
traceviewpp
trackbar
trackpad
transitioning
Trd
TREX
triaged
triaging
TRIMZEROHEADINGS
@ -1841,9 +1730,7 @@ trx
tsa
tsgr
tsm
TStr
TSTRFORMAT
TSub
TTBITMAP
TTFONT
TTFONTLIST
@ -1852,7 +1739,6 @@ TTo
tvpp
tvtseq
TYUI
UAC
uap
uapadmin
UAX
@ -1888,7 +1774,6 @@ unk
unknwn
UNORM
unparseable
Unregistering
untextured
UPDATEDISPLAY
UPDOWN
@ -1906,7 +1791,6 @@ USEFILLATTRIBUTE
USEGLYPHCHARS
USEHICON
USEPOSITION
USERDATA
userdpiapi
Userp
userprivapi
@ -1919,7 +1803,6 @@ USRDLL
utext
utr
UVWXY
UVWXYZ
uwa
uwp
uwu
@ -1928,17 +1811,16 @@ Vanara
vararg
vclib
vcxitems
vectorize
VERCTRL
VERTBAR
VFT
vga
vgaoem
viewkind
viewports
VIRAMA
Virt
VIRTTERM
visualstudiosdk
vkey
VKKEYSCAN
VMs
@ -1997,7 +1879,6 @@ wekyb
wewoad
wex
wextest
wextestclass
WFill
wfopen
WHelper
@ -2008,9 +1889,7 @@ Wiggum
wil
WImpl
WINAPI
winbase
winbasep
wincodec
wincon
winconp
winconpty
@ -2025,10 +1904,8 @@ windll
WINDOWALPHA
windowdpiapi
WINDOWEDGE
windowext
WINDOWINFO
windowio
windowmetrics
WINDOWPLACEMENT
windowpos
WINDOWPOSCHANGED
@ -2036,20 +1913,15 @@ WINDOWPOSCHANGING
windowproc
windowrect
windowsapp
windowsinternalstring
WINDOWSIZE
windowsshell
windowsterminal
windowsx
windowtheme
winevent
wingdi
winget
wingetcreate
WINIDE
winioctl
winmd
winmeta
winmgr
winmm
WINMSAPP
@ -2059,8 +1931,8 @@ WInplace
winres
winrt
winternl
winui
winuser
winuserp
WINVER
wistd
wmain
@ -2097,10 +1969,9 @@ WRITECONSOLEINPUT
WRITECONSOLEOUTPUT
WRITECONSOLEOUTPUTSTRING
wrkstr
wrl
WRL
wrp
WRunoff
wsl
WSLENV
wstr
wstrings
@ -2113,7 +1984,7 @@ wtof
WTs
WTSOFTFONT
wtw
wtypes
Wtypes
WUX
WVerify
WWith
@ -2132,7 +2003,6 @@ XBUTTONDOWN
XBUTTONUP
XCast
XCENTER
xchar
xcopy
XCount
xdy
@ -2142,6 +2012,7 @@ XFG
XFile
XFORM
XIn
xkcd
XManifest
XMath
XNamespace
@ -2168,7 +2039,6 @@ YLimit
YPan
YSubstantial
YVIRTUALSCREEN
Zab
zabcd
Zabcdefghijklmn
Zabcdefghijklmnopqrstuvwxyz
@ -2177,4 +2047,3 @@ ZCtrl
ZWJs
ZYXWVU
ZYXWVUTd
zzf

View File

@ -8,6 +8,24 @@
# you might not want to check in code where you skip all the other tests.
#\bfit\(
# English does not use a hyphen between adverbs and nouns
# https://twitter.com/nyttypos/status/1894815686192685239
(?:^|\s)[A-Z]?[a-z]+ly-(?=[a-z]{3,})(?:[.,?!]?\s|$)
# Don't use `requires that` + `to be`
# https://twitter.com/nyttypos/status/1894816551435641027
\brequires that \w+\b[^.]+to be\b
# A fully parenthetical sentences period goes inside the parentheses, not outside.
# https://twitter.com/nyttypos/status/1898844061873639490
\([A-Z][a-z]{2,}(?: [a-z]+){3,}\)\.\s
# Complete sentences shouldn't be in the middle of another sentence as a parenthetical.
(?<!\.)(?<!\betc)\.\),
# Complete sentences in parentheticals should not have a space before the period.
\s\.\)(?!.*\}\})
# Should be `HH:MM:SS`
\bHH:SS:MM\b
@ -24,18 +42,52 @@
# Should be `a priori` or `and prior`
(?i)(?<!posteriori)\sand priori\s
# Should be `a`
\san (?=(?:[b-df-gj-np-rtv-xz]|h(?!our|sl|tml|ttp)|s(?!sh|vg))[a-z])
# Should only be one of `a`, `an`, or `the`
\b(?:(?:an?|the)\s+){2,}\b
# Should only be `are` or `can`, not both
\b(?:(?:are|can)\s+){2,}\b
# Should probably be `ABCDEFGHIJKLMNOPQRSTUVWXYZ`
(?i)(?!ABCDEFGHIJKLMNOPQRSTUVWXYZ)ABC[A-Z]{21}YZ
# Should be `an`
(?<!\b[Ii] )\bam\b
# Should be `anymore`
\bany more[,.]
# Should be `Ask`
(?:^|[.?]\s+)As\s+[A-Z][a-z]{2,}\s[^.?]*?(?:how|if|wh\w+)\b
# Should be `at one fell swoop`
# and only when talking about killing, not some other completion
# Act 4 Scene 3, Macbeth
# https://www.opensourceshakespeare.org/views/plays/play_view.php?WorkID=macbeth&Act=4&Scene=3&Scope=scene
\bin one fell s[lw]?oop\b
# Should be `'`
(?i)\b(?:(?:i|s?he|they|what|who|you)"ll|(?:are|ca|did|do|does|ha[ds]|have|is|should|were|wo|would)n"t|(?:s?he|let|that|there|what|where|who)"s|(?:i|they|we|what|who|you)"ve)\b
(?i)\b(?:(?:i|s?he|they|what|who|you)[`"]ll|(?:are|ca|did|do|does|ha[ds]|have|is|should|were|wo|would)n[`"]t|(?:s?he|let|that|there|what|where|who)[`"]s|(?:i|they|we|what|who|you)[`"]ve)\b
# Should be `background` / `intro text` / `introduction` / `prologue` unless it's a brand or relates to _subterfuge_
(?i)\bpretext\b
# Should be `bearer`
\b(?<=the )burden(?= of bad news\b)
# Should be `branches`
# ... unless it's really about the meal that replaces breakfast and lunch.
\b[Bb]runches\b
# Should be `briefcase`
\bbrief-case\b
# Should be `by far` or `far and away`
\bby far and away\b
# Should be `can, not only ..., ... also...`
\bcan not only.*can also\b
@ -46,7 +98,10 @@
# > In formal writing and where contractions are frowned upon, use `cannot`.
# > It is possible to write `can not`, but you generally find it only as part of some other construction, such as `not only . . . but also.`
# - if you encounter such a case, add a pattern for that case to patterns.txt.
\b[Cc]an not\b
\b[Cc]an not\b(?! only\b)
# Should be `chart`
(?i)\bhelm\b.*\bchard\b
# Do not use `(click) here` links
# For more information, see:
@ -56,9 +111,27 @@
# * https://heyoka.medium.com/dont-use-click-here-f32f445d1021
(?i)(?:>|\[)(?:(?:click |)here|link|(?:read |)more)(?:</|\]\()
# Including "image of" or "picture of" in alt text is unnecessary.
\balt=['"](?:an? |)(?:image|picture) of
# Alt text should be short
\balt=(?:'[^']{126,}'|"[^"]{126,}")
# Should be `equals` to `is equal to`
\bequals to\b
# Should be `ECMA` 262 (JavaScript)
(?i)\bTS\/EMCA\b|\bEMCA(?: \d|\s*Script)|\bEMCA\b(?=.*\bTS\b)
# Should be `ECMA` 340 (Near Field Communications)
(?i)EMCA[- ]340
# Should be `fall back`
(?<!\ba )(?<!\bthe )\bfallback(?= to(?! ask))\b
# Should be `for`, `for, to` or `to`
\b(?:for to|to for)\b
# Should be `GitHub`
(?<![&*.]|// |\b(?:from|import|type) )\bGithub\b(?![{()])
@ -84,11 +157,14 @@
# Should be `RabbitMQ`
\bRabbitmq\b
# Should be `TensorFlow`
\bTensorflow\b
# Should be `TypeScript`
\bTypescript\b
# Should be `another`
\ban[- ]other\b
\ban[- ]other(?!-)\b
# Should be `case-(in)sensitive`
\bcase (?:in|)sensitive\b
@ -108,11 +184,14 @@
# Should be `here-in`, `the`, `them`, `this`, `these` or reworded in some other way
\bthe here(?:\.|,| (?!and|defined))
# Should be `going to bed` or `going to a bad`
\bgoing to bad(?!-)\b
# Should be `greater than`
#\bhigher than\b
# Should be `ID`
#\bId\b
# Should be `ID` (unless it's a flag/property)
#(?<![-\.])\bId\b(?![(])
# Should be `in front of`
\bin from of\b
@ -125,6 +204,12 @@
# Should be `use`
\sin used by\b
# Should be `in-depth` if used as an adjective (but `in depth` when used as an adverb)
\bin depth\s(?!rather\b)\w{6,}
# Should be `in-flight` or `on the fly` (unless actually talking about airline flights)
\bon[- ]flight\b(?!=\s+(?:(?:\w{2}|)\d+|availability|booking|computer|data|delay|departure|management|performance|radar|reservation|scheduling|software|status|ticket|time|type|.*(?:hotel|taxi)))
# Should be `is obsolete`
\bis obsolescent\b
@ -132,7 +217,10 @@
\bits[']
# Should be `its`
\bit's(?= own\b)
\bit's(?= (?:child|only purpose|own(?:er|)|parent|sibling)\b)
# Should be `for its` (possessive) or `because it is`
\bfor it(?:'s| is)\b
# Should be `log in`
\blogin to the
@ -140,6 +228,25 @@
# Should be `long-standing`
\blong standing\b
# Should be `lose`
(?<=\bwill )loose\b
# `apt-key` is deprecated
# ... instead you should be writing a pair of files:
# ... * the gpg key added to a distinct key ring file based on your project/distro/key...
# ... * the sources.list in a district file -- not simply appended to `/etc/apt/sources.list` -- (there is a newer format [DEB822](https://manpages.debian.org/bookworm/dpkg-dev/deb822.5.en.html)) that references the gpg key.
# Consider:
# ````sh
# curl http://download.something.example.com/$DISTRO/Release.key | \
# gpg --dearmor --yes --output /usr/share/keyrings/something-distro.gpg
# echo "deb [signed-by=/usr/share/keyrings/something-distro.gpg] http://download.something.example.com/repositories/home:/$DISTRO ./" \
# >> /etc/apt/sources.list.d/something-distro.list
# ````
\bapt-key add\b
# Should be `nearby`
\bnear by\b
# Should probably be a person named `Nick` or the abbreviation `NIC`
\bNic\b
@ -153,7 +260,7 @@
\bperform it's\b
# Should be `opt-in`
#(?<!\scan|for)(?<!\sif)\sopt in\s
#(?<!\scan|for)(?<!\smust)(?<!\sif)\sopt in\s
# Should be `less than`
\bless then\b
@ -170,24 +277,77 @@
# Should be `on the other hand`
\b(?i)on another hand\b
# Reword to `on at runtime` or `enabled at launch`
# The former if you mean it can be changed dynamically.
# The latter if you mean that it can be changed without recompiling but not after the program starts.
\bswitched on runtime\b
# Should be `Of course,`
[?.!]\s+Of course\s(?=[-\w\s]+[.?;!,])
# Most people only have two hands. Reword.
\b(?i)on the third hand\b
# Should be `Open Graph`
# unless talking about a specific Open Graph implementation:
# - Java
# - Node
# - Py
# - Ruby
\bOpenGraph\b
# Should be `OpenShift`
\bOpenshift\b
# Should be `otherwise`
\bother[- ]wise\b
# Should be `; otherwise` or `. Otherwise`
# https://study.com/learn/lesson/otherwise-in-a-sentence.html
, [Oo]therwise\b
# Should probably be `Otherwise,`
(?<=\. )Otherwise\s
# Should be `or (more|less)`
\bore (?:more|less)\b
# Should be reworded.
# `passthrough` is an adjective
# `pass-through` could be a noun
# `pass through` would be a verb phrase
\b(?i)passthrough(?= an?\b)
# Should be `rather than`
\brather then\b
# Should be `Red Hat`
\bRed[Hh]at\b
# Should be `regardless, ...` or `regardless of (whether)`
\b[Rr]egardless if you\b
# Should be `self-signed`
\bself signed\b
# Should be `SendGrid`
\bSendgrid\b
# Should be `set up` (`setup` is a noun / `set up` is a verb)
\b[Ss]etup(?= (?:an?|the)\b)
# Should be `state`
\bsate(?=\b|[A-Z])|(?<=[a-z])Sate(?=\b|[A-Z])|(?<=[A-Z]{2})Sate(?=\b|[A-Z])
# Should be `no longer needed`
\bno more needed\b(?! than\b)
# Should be `<see|look> below for the`
(?i)\bfind below the\b
# Should be `then any` unless there's a comparison before the `,`
, than any\b
# Should be `did not exist`
\bwere not existent\b
@ -197,9 +357,18 @@
# Should be `nonexistent`
\b[Nn]o[nt][- ]existent\b
# Should be `our`
\bspending out time\b
# Should be `@brief` / `@details` / `@param` / `@return` / `@retval`
(?:^\s*|(?:\*|//|/*)\s+`)[\\@](?:breif|(?:detail|detials)|(?:params(?!\.)|prama?)|ret(?:uns?)|retvl)\b
# Should be `more than` or `more, then`
\bmore then\b
# Should be `Pipeline`/`pipeline`
(?:(?<=\b|[A-Z])p|P)ipeLine(?:\b|(?=[A-Z]))
# Should be `preexisting`
[Pp]re[- ]existing
@ -224,14 +393,27 @@
# Should be `reentrant`
[Rr]e[- ]entrant
# Should be `room for`
\brooms for (?!lease|rent|sale)
# Should be `socioeconomic`
# https://dictionary.cambridge.org/us/dictionary/english/socioeconomic
socio-economic
# Should be `strong suit`
\b(?:my|his|her|their) strong suite\b
# Should probably be `temperatures` unless actually talking about thermal drafts (things birds may fly on)
\bthermals\b
# Should be `there are` or `they are` (or `they're`)
(?i)\btheir are\b
# Should be `understand`
\bunder stand\b
# Should be `URI` or `uri` unless it refers to a person named `Uri`
#(?<!\.)\bUri\b(?![(])
# Should be `URI` or `uri` unless it refers to a person named `Uri` (or a flag)
#(?<![-\.])\bUri\b(?![(])
# Should be `it uses is`
/\bis uses is\b/
@ -245,12 +427,36 @@
# Should be `where`
\bwere they are\b
# Should be `why`
, way(?= is [^.]*\?)
# should be `vCenter`
\bV[Cc]enter\b
# Should be `VM`
\bVm\b
# Should be `walkthrough(s)`
\bwalk-throughs?\b
# Should be `want`
\bdon't ant\b
# Should be `we'll`
\bwe 'll\b
# Should be `whereas`
\bwhere as\b
# Should be `WinGet`
\bWinget\b
# Should be `without` (unless `out` is a modifier of the next word)
\bwith out\b(?!-)
# Should be `work around`
\b[Ww]orkaround(?= an?\b)
# Should be `workarounds`
#\bwork[- ]arounds\b
@ -270,12 +476,12 @@
\b(?:coarse|fine) grained\b
# Homoglyph (Cyrillic) should be `A`/`B`/`C`/`E`/`H`/`I`/`I`/`J`/`K`/`M`/`O`/`P`/`S`/`T`/`Y`
# It's possible that your content is intentionally mixing Cyrllic and Latin scripts, but if it isn't, you definitely want to correct this.
# It's possible that your content is intentionally mixing Cyrillic and Latin scripts, but if it isn't, you definitely want to correct this.
(?<=[A-Z]{2})[АВСЕНІӀЈКМОРЅТУ]|[АВСЕНІӀЈКМОРЅТУ](?=[A-Z]+(?:\b|[a-z]+)|[a-z]+(?:[^a-z]|$))
# Homoglyph (Cyrillic) should be `a`/`b`/`e`
# It's possible that your content is intentionally mixing Cyrllic and Latin scripts, but if it isn't, you definitely want to correct this.
[аве](?=[A-Za-z]{2,})|(?<=[A-Za-z]{2})[аве]|(?<=[A-Za-z])[аве](?=[A-Za-z])
# Homoglyph (Cyrillic) should be `a`/`b`/`c`/`e`/`o`/`p`/`x`/`y`
# It's possible that your content is intentionally mixing Cyrillic and Latin scripts, but if it isn't, you definitely want to correct this.
[авсеорху](?=[A-Za-z]{2,})|(?<=[A-Za-z]{2})[авсеорху]|(?<=[A-Za-z])[авсеорху](?=[A-Za-z])
# Should be `neither/nor` -- or reword
#(?!<do )\bnot\b([^.?!"/(](?!neither|,.*?,))+\bnor\b

View File

@ -1,5 +1,35 @@
# See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns
# Windows accelerators
\b[A-Z][a-z]*&[a-z]+(?!;)\b
# charsets.hpp
\{ L.*\}, // (?:Cyrillic|Greek|Hebrew).*
# Screen buffer tests
\bQQ[A-Z]+\s*[A-Z]*Q+\b
# Unicode references
(?<=\W)(?:U\+?|)[0-9A-F]+b?\b
# Verify
VERIFY_IS_TRUE\(.*\)
# TEST_METHOD(ApiScrollConsoleScreenBufferW)
\bZ[A-Z]+$
# TerminalApiTest
stateMachine\.ProcessString\(L".*"
# bundles
[0-9a-z]+\\?\.msixbundle
# text file names
"[a-z]+\.txt"
# Checksum
L"[0-9A-F]{4}"
# Direct 2D/3D
\b(?:d[23]d(?=[a-z])|D[23]D(?=[A-Z]))
@ -9,39 +39,127 @@
# Windows Resources with accelerators
\b[A-Z]&[a-z]+\b(?!;)
# bug in check-spelling v0.0.24 (fixed later)
\bok'd\b
# Automatically suggested patterns
# hit-count: 83 file-count: 18
# hit-count: 3904 file-count: 577
# IServiceProvider / isAThing
(?:(?:\b|_|(?<=[a-z]))[IT]|(?:\b|_)(?:nsI|isA))(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
# hit-count: 2437 file-count: 826
# #includes
^\s*#include\s*(?:<.*?>|".*?")
# hit-count: 1131 file-count: 326
# C# includes
^\s*using [^;]+;
# hit-count: 128 file-count: 47
# C network byte conversions
(?:\d|\bh)to(?!ken)(?=[a-z])|to(?=[adhiklpun]\()
# hit-count: 59 file-count: 36
# IServiceProvider / isAThing
(?:\b|_)(?:(?:ns|)I|isA)(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b))
# hit-count: 53 file-count: 10
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\\03[1-7]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+)*m
# hit-count: 9 file-count: 6
# hit-count: 45 file-count: 29
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# hit-count: 30 file-count: 19
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hit-count: 17 file-count: 7
# File extensions
\*\.[+\w]+,
# hit-count: 15 file-count: 9
# Markdown anchor links
\(#\S*?[a-zA-Z]\S*?\)
# hit-count: 5 file-count: 5
# libraries
(?:\b|_)lib(?:re(?=office)|)(?!era[lt]|ero|ert(?:ies|y)|rar(?:i(?:an|es)|y))(?=[a-z])
# hit-count: 14 file-count: 8
# hex runs
\b[0-9a-fA-F]{16,}\b
# hit-count: 12 file-count: 8
# hex digits including css/html color classes:
(?:[\\0][xX]|\\u|[uU]\+|#x?|%23|&H)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b
# hit-count: 12 file-count: 7
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# hit-count: 9 file-count: 6
# Repeated letters
\b([a-z])\g{-1}{2,}\b
# hit-count: 8 file-count: 2
# regex choice
\(\?:[^)]+\|[^)]+\)
# hit-count: 8 file-count: 1
# latex (check-spelling >= 0.0.22)
\\\w{2,}\{
# hit-count: 7 file-count: 4
# Python string prefix / binary prefix
# 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,})
# hit-count: 5 file-count: 3
# Alternatively, if you're using check-spelling v0.0.25+, and you would like to _check_ the Non-English content for spelling errors, you can. For information on how to do so, see:
# https://docs.check-spelling.dev/Feature:-Configurable-word-characters.html#unicode
[a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
# hit-count: 3 file-count: 3
# File extensions
\*\.[+\w]+,
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@._]{3,}
# hit-count: 2 file-count: 2
# Alternative printf
# %s
%(?:s(?=[a-z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%[^s])\b)(?=.*?['"])
# hit-count: 2 file-count: 1
# kubernetes crd patterns
^\s*pattern: .*$
# hit-count: 1 file-count: 1
# css fonts
\bfont(?:-family|):[^;}]+
# hit-count: 1 file-count: 1
# microsoft
\b(?:https?://|)(?:(?:(?:blogs|download\.visualstudio|docs|msdn2?|research)\.|)microsoft|blogs\.msdn)\.co(?:m|\.\w\w)/[-_a-zA-Z0-9()=./%]*
# hit-count: 1 file-count: 1
# Punycode
\bxn--[-0-9a-z]+
# hit-count: 1 file-count: 1
# sha-... -- uses a fancy capture
(\\?['"]|&quot;)[0-9a-f]{40,}\g{-1}
# hit-count: 1 file-count: 1
# Docker images
^\s*(?i)FROM\s+\S+:\S+(?:\s+AS\s+\S+|)
# hit-count: 1 file-count: 1
# WWNN/WWPN (NAA identifiers)
\b(?:0x)?10[0-9a-f]{14}\b|\b(?:0x|3)?[25][0-9a-f]{15}\b|\b(?:0x|3)?6[0-9a-f]{31}\b
# hit-count: 1 file-count: 1
# curl arguments
\b(?:\\n|)curl(?:\.exe|)(?:\s+-[a-zA-Z]{1,2}\b)*(?:\s+-[a-zA-Z]{3,})(?:\s+-[a-zA-Z]+)*
# hit-count: 1 file-count: 1
# 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
# bug in check-spelling v0.0.24 (fixed later)
\bok'd\b
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)
@ -72,24 +190,11 @@ ROY\sG\.\sBIV
# ARM NEON intrinsics like "vsubq_u16"
\bv\w+_[fsu](?:8|16|32|64)\b
# color floating numbers
0x[0-9a-f](?:\.[0-9a-f]*p)[-+]\d+f
# AppX package
_\d[0-9a-z]{12}['\.]
# string test
equals_insensitive_ascii\("\w+", "\w+"
# Automatically suggested patterns
# hit-count: 3788 file-count: 599
# IServiceProvider / isAThing
\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b)
# hit-count: 314 file-count: 21
# hex runs
\b[0-9a-fA-F]{16,}\b
# hit-count: 47 file-count: 11
# special cased printf markers
\\r\\n(?=[a-z])|(?<!\\)\\[nrt](?=[a-z]{2,})(?=.*(?:<.*['"`]|"(?:[;,]|\);)$|\) \+$))
@ -97,84 +202,6 @@ equals_insensitive_ascii\("\w+", "\w+"
# ConsoleArgumentsTests
--headless\\.*?"
# hit-count: 109 file-count: 62
# Compiler flags (Unix, Java/Scala)
# Use if you have things like `-Pdocker` and want to treat them as `docker`
(?:^|[\t ,>"'`=(])-(?:D(?=[A-Z])|W(?!ork)|X|f(?=[ms]))(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,})
# hit-count: 60 file-count: 35
# version suffix <word>v#
(?:(?<=[A-Z]{2})V|(?<=[a-z]{2}|[A-Z]{2})v)\d+(?:\b|(?=[a-zA-Z_]))
# hit-count: 2 file-count: 2
# This does not cover multiline strings, if your repository has them,
# you'll want to remove the `(?=.*?")` suffix.
# The `(?=.*?")` suffix should limit the false positives rate
# printf
%(?:s)(?!ize)(?=[a-z]{2,})
# hit-count: 16 file-count: 10
# uuid:
\b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b
# hit-count: 13 file-count: 4
# Non-English
[a-zA-Z]*[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3}[a-zA-ZÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]*|[a-zA-Z]{3,}[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź]|[ÀÁÂÃÄÅÆČÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæčçèéêëìíîïðñòóôõöøùúûüýÿĀāŁłŃńŅņŒœŚśŠšŜŝŸŽžź][a-zA-Z]{3,}
# hit-count: 7 file-count: 5
# 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}|[iu]\d+)\b
# hit-count: 7 file-count: 1
# regex choice
\(\?:[^)]+\|[^)]+\)
# hit-count: 4 file-count: 4
# tar arguments
\b(?:\\n|)g?tar(?:\.exe|)(?:(?:\s+--[-a-zA-Z]+|\s+-[a-zA-Z]+|\s[ABGJMOPRSUWZacdfh-pr-xz]+\b)(?:=[^ ]*|))+
# hit-count: 4 file-count: 1
# ANSI color codes
(?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m
# hit-count: 4 file-count: 1
# 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|[,.])*
# hit-count: 3 file-count: 3
# mailto urls
mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
# hit-count: 2 file-count: 1
# Python string prefix / binary prefix
# 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,})
# hit-count: 1 file-count: 1
# Punycode
\bxn--[-0-9a-z]+
# hit-count: 1 file-count: 1
# latex (check-spelling >= 0.0.22)
\\\w{2,}\{
# hit-count: 1 file-count: 1
# 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
# Questionably acceptable forms of `in to`
# Personally, I prefer `log into`, but people object
# https://www.tprteaching.com/log-into-log-in-to-login/
\b(?:[Ll]og|[Ss]ign) in to\b
# to opt in
\bto opt in\b
# Questionably acceptable forms of `in to`
# Personally, I prefer `log into`, but people object
@ -183,6 +210,10 @@ mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,}
# to opt in
\bto opt in\b
# pass(ed|ing) in
\bpass(?:ed|ing) in\b
# acceptable duplicates
# ls directory listings
[-bcdlpsw](?:[-r][-w][-SsTtx]){3}[\.+*]?\s+\d+\s+\S+\s+\S+\s+[.\d]+(?:[KMGT]|)\s+

View File

@ -1,10 +1,19 @@
^attache$
^attacher$
^attachers$
^bellow$
^bellow?$
benefitting
occurences?
^dependan.*
^develope$
^developement$
^developpe
^Devers?$
^devex
^devide
^Devinn?[ae]
^devisal
^devisor
^diables?$
^oer$
Sorce
@ -12,4 +21,5 @@ Sorce
^Teh$
^untill$
^untilling$
^venders?$
^wether.*

View File

@ -93,7 +93,7 @@ jobs:
steps:
- name: check-spelling
id: spelling
uses: check-spelling/check-spelling@v0.0.24
uses: check-spelling/check-spelling@v0.0.25
with:
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
checkout: true
@ -104,7 +104,7 @@ jobs:
report-timing: 1
warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check,unclosed-block-ignore-begin,unclosed-block-ignore-end
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }}
use_sarif: 1
check_extra_dictionaries: ""
dictionary_source_prefixes: >
{
@ -114,34 +114,33 @@ jobs:
cspell:software-terms/softwareTerms.txt
cspell:cpp/stdlib-cpp.txt
cspell:cpp/stdlib-c.txt
cspell:lorem-ipsum/dictionary.txt
cspell:python/python/python-lib.txt
cspell:php/php.txt
cspell:node/node.txt
cspell:dart/dart.txt
cspell:filetypes/filetypes.txt
cspell:java/java.txt
cspell:node/node.txt
cspell:golang/go.txt
cspell:java/java-terms.txt
cspell:mnemonics/mnemonics.txt
cspell:css/css.txt
cspell:dotnet/dotnet.txt
cspell:npm/npm.txt
cspell:fullstack/fullstack.txt
cspell:python/python/python-lib.txt
cspell:dotnet/dotnet.txt
cspell:dart/dart.txt
cspell:aws/aws.txt
cspell:python/common/extra.txt
cspell:css/css.txt
cspell:java/java-terms.txt
cspell:r/r.txt
cspell:golang/go.txt
cspell:cpp/stdlib-cmath.txt
cspell:typescript/typescript.txt
cspell:html/html.txt
cspell:cpp/compiler-msvc.txt
cspell:django/django.txt
cspell:html/html.txt
cspell:cpp/lang-keywords.txt
cspell:aws/aws.txt
cspell:python/common/extra.txt
cspell:cpp/ecosystem.txt
cspell:r/r.txt
cspell:cpp/compiler-clang-attributes.txt
cspell:powershell/powershell.txt
cspell:cpp/lang-keywords.txt
cspell:csharp/csharp.txt
cspell:cpp/compiler-clang-attributes.txt
cspell:python/python/python.txt
cspell:mnemonics/mnemonics.txt
cspell:powershell/powershell.txt
comment-push:
name: Report (Push)
@ -154,7 +153,7 @@ jobs:
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.24
uses: check-spelling/check-spelling@v0.0.25
with:
checkout: true
spell_check_this: microsoft/terminal@main
@ -172,7 +171,7 @@ jobs:
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
steps:
- name: comment
uses: check-spelling/check-spelling@v0.0.24
uses: check-spelling/check-spelling@v0.0.25
with:
checkout: true
spell_check_this: microsoft/terminal@main
@ -198,7 +197,7 @@ jobs:
cancel-in-progress: false
steps:
- name: apply spelling updates
uses: check-spelling/check-spelling@v0.0.24
uses: check-spelling/check-spelling@v0.0.25
with:
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
checkout: true

View File

@ -1,4 +1,4 @@
name: Publish to Winget
name: Publish to WinGet
on:
release:
@ -6,6 +6,9 @@ on:
env:
REGEX: 'Microsoft\.WindowsTerminal(?:Preview)?_([\d.]+)_8wekyb3d8bbwe\.msixbundle$'
# winget-create will read the following environment variable to access the GitHub token needed for submitting a PR
# See https://aka.ms/winget-create-token
WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_TOKEN }}
jobs:
publish:
@ -21,4 +24,4 @@ jobs:
$wingetPackage = "Microsoft.WindowsTerminal${{ github.event.release.prerelease && '.Preview' || '' }}"
& curl.exe -JLO https://aka.ms/wingetcreate/latest
& .\wingetcreate.exe update $wingetPackage -s -v $version -u $wingetRelevantAsset.browser_download_url -t "${{ secrets.WINGET_TOKEN }}"
& .\wingetcreate.exe update $wingetPackage -s -v $version -u $wingetRelevantAsset.browser_download_url

View File

@ -17,7 +17,6 @@
"Microsoft.VisualStudio.Component.AppInsights.Tools",
"Microsoft.Net.Component.4.8.TargetingPack",
"Microsoft.VisualStudio.Component.DiagnosticTools",
"Microsoft.NetCore.Component.Runtime.6.0",
"Microsoft.VisualStudio.Component.ClassDesigner",
"Microsoft.VisualStudio.Component.GraphDocument",
"Microsoft.VisualStudio.Component.CodeMap",

View File

@ -285,6 +285,8 @@ specific language governing permissions and limitations under the License.
**Source**: [https://github.com/commonmark/cmark](https://github.com/commonmark/cmark)
### License
```
Copyright (c) 2014, John MacFarlane
All rights reserved.
@ -455,6 +457,36 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## fzf
### License
```
The MIT License (MIT)
Copyright (c) 2013-2024 Junegunn Choi
Copyright (c) 2021-2025 Simon Hauser
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
```
# Microsoft Open Source

View File

@ -504,7 +504,7 @@ namespace HelixTestHelpers
assembly.SetAttributeValue("run-date", DateTime.Now.ToString("yyyy-MM-dd"));
// This doesn't need to be completely accurate since it's not exposed anywhere.
// If we need accurate an start time we can probably calculate it from the te.wtl file, but for
// If we need an accurate start time we can probably calculate it from the te.wtl file, but for
// now this is fine.
assembly.SetAttributeValue("run-time", (DateTime.Now - testPass.TestPassExecutionTime).ToString("hh:mm:ss"));

View File

@ -2,7 +2,7 @@
{
"MatchedPath": [
"WpfTerminalControl/net472/Microsoft.Terminal.Wpf.dll",
"WpfTerminalControl/net6.0-windows/Microsoft.Terminal.Wpf.dll"
"WpfTerminalControl/net8.0-windows/Microsoft.Terminal.Wpf.dll"
],
"SigningInfo": {
"Operations": [

View File

@ -14,21 +14,21 @@
<Package
Name="Microsoft.UI.Xaml.2.8"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="8.2305.5001.0"
Version="8.2306.22001.0"
ProcessorArchitecture="x64"
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.x64.appx" />
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.5/Microsoft.UI.Xaml.2.8.x64.appx" />
<Package
Name="Microsoft.UI.Xaml.2.8"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="8.2305.5001.0"
Version="8.2306.22001.0"
ProcessorArchitecture="x86"
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.x86.appx" />
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.5/Microsoft.UI.Xaml.2.8.x86.appx" />
<Package
Name="Microsoft.UI.Xaml.2.8"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="8.2305.5001.0"
Version="8.2306.22001.0"
ProcessorArchitecture="arm64"
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.4/Microsoft.UI.Xaml.2.8.arm64.appx" />
Uri="https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.5/Microsoft.UI.Xaml.2.8.arm64.appx" />
</Dependencies>
<UpdateSettings>

View File

@ -50,6 +50,7 @@ extends:
parameters:
pool: { type: windows }
variables:
ob_sdl_prefast_enabled: false # This is a collection of powershell scripts
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true
ob_outputDirectory: "$(Build.SourcesDirectory)/_none"

View File

@ -75,13 +75,30 @@ jobs:
}
displayName: "Wrangle Unpackaged builds into place, rename"
- task: AzurePowerShell@5
- task: PowerShell@2
displayName: Install Azure Modules from custom PowerShell Gallery Repo
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
pwsh: false # We are preparing modules for AzureFileCopy, which uses PowerShell 5.1
targetType: inline
script: |-
$MachineToken = $env:SYSTEM_ACCESSTOKEN | ConvertTo-SecureString -AsPlainText -Force
$Credential = [PSCredential]::new("ONEBRANCH_TOKEN", $MachineToken)
$MachineToken = $null
$Feed = "https://pkgs.dev.azure.com/shine-oss/terminal/_packaging/TerminalDependencies/nuget/v3/index.json"
Register-PSResourceRepository -Name "PSGalleryUpstream" -Uri $Feed -Trusted
Get-PSResourceRepository
Install-PSResource -Name Az.Accounts, Az.Storage, Az.Network, Az.Resources, Az.Compute -Repository "PSGalleryUpstream" -Credential $Credential
- task: AzureFileCopy@6
displayName: Publish to Storage Account
inputs:
sourcePath: _out/*
Destination: AzureBlob
azureSubscription: ${{ parameters.subscription }}
azurePowerShellVersion: LatestVersion
pwsh: true
ScriptType: InlineScript
Inline: |-
$Env:AZCOPY_AUTO_LOGIN_TYPE="PSCRED"
& AzCopy copy "_out\*" "https://${{ parameters.storageAccount }}.blob.core.windows.net/${{ parameters.storageContainer }}/" --content-type application/octet-stream
storage: ${{ parameters.storageAccount }}
ContainerName: ${{ parameters.storageContainer }}
AdditionalArgumentsForBlobCopy: "--content-type application/octet-stream"

View File

@ -30,7 +30,7 @@ jobs:
steps:
- checkout: self
clean: true
# It is important that this be 0, otherwise git will not fetch the branch ref names that the PGO rules require.
# It is important that this be 0; otherwise, git will not fetch the branch ref names that the PGO rules require.
fetchDepth: 0
submodules: false
persistCredentials: false

View File

@ -61,7 +61,7 @@ jobs:
pwsh: true
ScriptType: InlineScript
Inline: |-
$AzToken = (Get-AzAccessToken -ResourceUrl api://30471ccf-0966-45b9-a979-065dbedb24c1).Token
$AzToken = (Get-AzAccessToken -AsSecureString -ResourceUrl api://30471ccf-0966-45b9-a979-065dbedb24c1).Token | ConvertFrom-SecureString -AsPlainText
Write-Host "##vso[task.setvariable variable=SymbolAccessToken;issecret=true]$AzToken"

View File

@ -88,6 +88,9 @@ extends:
enabled: false
globalSdl: # https://aka.ms/obpipelines/sdl
enableCheckCFlags: false # CheckCFlags is broken and exploding our builds; to remove, :g/BAD-FLAGS/d
isNativeCode: true
prefast:
enabled: true
asyncSdl:
enabled: true
tsaOptionsFile: 'build/config/tsa.json'
@ -115,6 +118,8 @@ extends:
variables:
ob_sdl_checkcflags_enabled: false # BAD-FLAGS
ob_sdl_xfgcheck_enabled: false # BAD-FLAGS
ob_sdl_prefast_runDuring: Build
ob_sdl_checkCompliantCompilerWarnings: true
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true
ob_outputDirectory: $(JobOutputDirectory)
@ -149,6 +154,7 @@ extends:
variables:
ob_sdl_checkcflags_enabled: false # BAD-FLAGS
ob_sdl_xfgcheck_enabled: false # BAD-FLAGS
ob_sdl_prefast_enabled: false # This is a C# build job
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true
ob_outputDirectory: $(JobOutputDirectory)
@ -180,6 +186,7 @@ extends:
variables:
ob_sdl_checkcflags_enabled: false # BAD-FLAGS
ob_sdl_xfgcheck_enabled: false # BAD-FLAGS
ob_sdl_prefast_enabled: false # This is a collection of powershell scripts
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true
ob_outputDirectory: $(JobOutputDirectory)
@ -234,6 +241,7 @@ extends:
variables:
ob_sdl_checkcflags_enabled: false # BAD-FLAGS
ob_sdl_xfgcheck_enabled: false # BAD-FLAGS
ob_sdl_prefast_enabled: false # This is a collection of powershell scripts
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true
ob_outputDirectory: $(JobOutputDirectory)
@ -252,6 +260,7 @@ extends:
variables:
ob_sdl_checkcflags_enabled: false # BAD-FLAGS
ob_sdl_xfgcheck_enabled: false # BAD-FLAGS
ob_sdl_prefast_enabled: false # This is a collection of powershell scripts
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true
ob_outputDirectory: $(JobOutputDirectory)
@ -277,6 +286,7 @@ extends:
variables:
ob_sdl_checkcflags_enabled: false # BAD-FLAGS
ob_sdl_xfgcheck_enabled: false # BAD-FLAGS
ob_sdl_prefast_enabled: false # This is a collection of powershell scripts
ob_git_checkout: false # This job checks itself out
ob_git_skip_checkout_none: true
ob_outputDirectory: $(Build.ArtifactStagingDirectory)

View File

@ -1,8 +1,28 @@
$VSInstances = ([xml](& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -include packages -format xml))
$VSPackages = $VSInstances.instances.instance.packages.package
$LatestVCPackage = ($VSInstances.instances.instance.packages.package | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
$LatestVCPackage = ($VSPackages | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
$LatestVCToolsVersion = $LatestVCPackage.version;
$VSRoot = (& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property 'resolvedInstallationPath')
$VCToolsRoot = Join-Path $VSRoot "VC\Tools\MSVC"
# We have observed a few instances where the VC tools package version actually
# differs from the version on the files themselves. We might as well check
# whether the version we just found _actually exists_ before we use it.
# We'll use whichever highest version exists.
$PackageVCToolPath = Join-Path $VCToolsRoot $LatestVCToolsVersion
If ($Null -Eq (Get-Item $PackageVCToolPath -ErrorAction:Ignore)) {
$VCToolsVersions = Get-ChildItem $VCToolsRoot | ForEach-Object {
[Version]$_.Name
} | Sort -Descending
$LatestActualVCToolsVersion = $VCToolsVersions | Select -First 1
If ([Version]$LatestVCToolsVersion -Ne $LatestActualVCToolsVersion) {
Write-Output "VC Tools Mismatch: Directory = $LatestActualVCToolsVersion, Package = $LatestVCToolsVersion"
$LatestVCToolsVersion = $LatestActualVCToolsVersion.ToString(3)
}
}
Write-Output "Latest VCToolsVersion: $LatestVCToolsVersion"
Write-Output "Updating VCToolsVersion environment variable for job"
Write-Output "##vso[task.setvariable variable=VCToolsVersion]$LatestVCToolsVersion"

View File

@ -7,5 +7,8 @@
<VersionMajor>1</VersionMajor>
<VersionMinor>24</VersionMinor>
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
<VersionInfoCulture>1033</VersionInfoCulture>
<!-- The default has a spacing problem -->
<VersionInfoCopyRight>\xa9 Microsoft Corporation. All rights reserved.</VersionInfoCopyRight>
</PropertyGroup>
</Project>

View File

@ -37,6 +37,6 @@ Presumably now you have a failure. Or a success. You can attempt to spelunk the
Now that you've relied on `testd` to get everything deployed and orchestrated and run once on the device, you can use `execd` to run things again or to run a smaller subset of things on the remote device through `T-Shell`.
By default, in the `Universal Test` world, everything will be deployed onto the remote machine at `C:\data\test\bin`. In T-Shell, use `cdd C:\data\test\bin` to change to that directory and then `execd te.exe Microsoft.Console.Host.FeatureTests.dll /name:*TestReadFileEcho*` to run just one specific test. Of course you should substitute the file name and test name parameters as makes sense. And of course you can find out more about `cdd` and `execd` on the `T-shell` page of `OSGWiki`.
By default, in the `Universal Test` world, everything will be deployed onto the remote machine at `C:\data\test\bin`. In T-Shell, use `cdd C:\data\test\bin` to change to that directory and then `execd te.exe Microsoft.Console.Host.FeatureTests.dll /name:*TestReadFileEcho*` to run just one specific test. Of course, you should substitute the file name and test name parameters as makes sense. And of course you can find out more about `cdd` and `execd` on the `T-shell` page of `OSGWiki`.
Fortunately, running things through `T-shell` in this fashion is exactly the same way that the testlab orchestrates the tests. If you still don't get good data this way, you can use the `Connect via Console` mechanism way above to try to run things under `WinDBG` or the `Visual Studio Remote Debugger` manually on the machine to get them to repro or under the debugger more completely.

View File

@ -32,13 +32,21 @@
]
},
"DynamicProfileSource": {
"type": "string",
"anyOf": [
{
"type": "string"
},
{
"enum": [
"Microsoft.WSL",
"Windows.Terminal.Wsl",
"Windows.Terminal.Azure",
"Windows.Terminal.PowershellCore",
"Windows.Terminal.VisualStudio"
],
"type": "string"
]
}
]
},
"BellStyle": {
"oneOf": [
@ -2368,6 +2376,16 @@
"description": "When set to true, the terminal will focus the pane on mouse hover.",
"type": "boolean"
},
"experimental.scrollToZoom": {
"default": true,
"description": "When set to true, holding the Ctrl key while scrolling will increase or decrease the terminal font size.",
"type": "boolean"
},
"experimental.scrollToChangeOpacity": {
"default": true,
"description": "When set to true, holding the Ctrl and Shift keys while scrolling will change the window opacity.",
"type": "boolean"
},
"compatibility.allowHeadless": {
"default": false,
"description": "When set to true, Windows Terminal will run in the background. This allows globalSummon and quakeMode actions to work even when no windows are open.",

View File

@ -51,4 +51,4 @@ DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
- If you hit a `Class not Registered` error, this might be because a class isn't getting registered in the app manifest. You can go check `src/cascadia/CascadiaPackage/bin/x64/Debug/AppX/AppXManifest.xml` to see if there exist entries to the classes of your newly created DLL. If the references aren't there, double check that you've added `<ProjectReference>` blocks to both `WindowsTerminal.vcxproj` and `TerminalApp.vcxproj`.
- If you hit an extremely vague error along the lines of `Error in the DLL`, and right before that line you notice that your new DLL is loaded and unloaded right after each other, double check that your new DLL's definitions show up in the `AppXManifest.xml` file. If your new DLL is included as a reference to a project that rolls up to `CascadiaPackage`, double check that you've created a `.def` file for the project. Otherwise if your new project _does not_ roll up to a package that populates the `AppXManifest` references for you, you'll have to add those references yourself.
- If you hit an extremely vague error along the lines of `Error in the DLL`, and right before that line you notice that your new DLL is loaded and unloaded right after each other, double check that your new DLL's definitions show up in the `AppXManifest.xml` file. If your new DLL is included as a reference to a project that rolls up to `CascadiaPackage`, double check that you've created a `.def` file for the project. Otherwise, if your new project _does not_ roll up to a package that populates the `AppXManifest` references for you, you'll have to add those references yourself.

View File

@ -9,7 +9,7 @@ issue id: 1564
## Abstract
Windows Terminal's settings model adheres to a cascading settings architecture. This allows a settings object to be defined incrementally across multiple layers of declarations. The value for any global setting like `copyOnSelect`, for example, is set to your settings.json value if one is defined, otherwise defaults.json, and otherwise a system set value. Profiles in particular are more complicated in that they must also take into account the values in `profiles.defaults` and dynamic profile generators.
Windows Terminal's settings model adheres to a cascading settings architecture. This allows a settings object to be defined incrementally across multiple layers of declarations. The value for any global setting like `copyOnSelect`, for example, is set to your settings.json value if one is defined; otherwise, defaults.json, and otherwise a system set value. Profiles in particular are more complicated in that they must also take into account the values in `profiles.defaults` and dynamic profile generators.
This spec explores how to represent this feature in the Settings UI.

View File

@ -529,7 +529,7 @@ their own workflows.
* `--local`: Save to the `.wt.json` in the CWD, if there is one (or create
one)
* `--parent`: Save to the `.wt.json` in the first ancestor of the CWD, if
there is one. Otherwise create one here.
there is one. Otherwise, create one here.
* `--settings`: Manually save to the settings file?
* `--profile`: save to this profile???? Not sure if this is actually possible.
Maybe with the `WT_SESSION_ID` env var to figure out which profile is in use

View File

@ -17,7 +17,7 @@ I work remotely as a developer, so I have to spend a lot of hours in front of my
Normally I like dark modes in all the programs and apps I use, but when there's too much sunlight, it becomes annoying, and sometimes even painful, to work in dark mode. So, I have all the programs and apps I use (at least, those that can) set to switch their color themes to what the system has.
The company I work for sent me a Macbook Pro, and my personal phone is an Android, both with automatic dark mode at sunset and light mode at sunrise, and in those devices it's been working relatively well. In Windows, as it is known, there's no such feature, so I manually change between dark and light mode when it's needed, and most of the programs and apps I use go along with this change. Windows Terminal, is not one of them.
The company I work for sent me a MacBook Pro, and my personal phone is an Android, both with automatic dark mode at sunset and light mode at sunrise, and in those devices it's been working relatively well. In Windows, as it is known, there's no such feature, so I manually change between dark and light mode when it's needed, and most of the programs and apps I use go along with this change. Windows Terminal, is not one of them.
The theme changes just as expected, but in an app like this, this change only affects the top of the window, leaving almost all of the screen at the mercy of what the color scheme is, and it doesn't depend on the theme, which defeats any attempt to make a good use of the `system` theme feature.

View File

@ -94,7 +94,7 @@ configurations:
- `"useExisting"`: always glom to the most recent window, regardless of desktop.
- `"useExistingOnSameDesktop"`: Only glom if there's an existing window on this
virtual desktop, otherwise create a new window. This will be the new default
virtual desktop; otherwise, create a new window. This will be the new default
value.
- `"useNew"`: Never glom, always create a new window. This is technically the
current behavior of the Terminal.

View File

@ -362,7 +362,7 @@ Essentially, the probabilistic elective monarchy will work in the following way:
register.
3. After registering as a server for `Monarch`s, attempt to create a `Monarch`
using `winrt::create_instance`.
4. Using that `Monarch`, ask it for it's PID.
4. Using that `Monarch`, ask it for its PID.
- If that PID is the same as the PID of the current process, then the window
process knows that it is the monarch.
- If that PID is some other process, then we know that we're not currently
@ -1102,7 +1102,7 @@ launch to use seems like an obvious next step. See also [#961].
- `true` or `"always"`: always glom to the most recent window, regardless of
desktop
- `"sameDesktop"`: Only glom if there's an existing window on this virtual
desktop, otherwise create a new window
desktop; otherwise, create a new window
- `false` or `"never"`: Never glom, always create a new window.

View File

@ -13,7 +13,7 @@ This spec is for feature request #605 "Search". It goes over the details of a ne
## Inspiration
One of the superior features of iTerm2 is it's content search. The search comes in two variants: search from active tab and search from all tabs. In almost any editor, there is an roughly equivalent string search. We also want to realize search experience in Terminal. There will be two variants, search within one tab or from multiple tabs. We will start with one-tab search implementation.
One of the superior features of iTerm2 is it's content search. The search comes in two variants: search from active tab and search from all tabs. In almost any editor, there is a roughly equivalent string search. We also want to realize search experience in Terminal. There will be two variants, search within one tab or from multiple tabs. We will start with one-tab search implementation.
## Solution Design

View File

@ -331,7 +331,7 @@ Are there other allocation policies we need to consider?
- requires coordination between tooling teams both within and without Microsoft (regarding any tool that operates on
or produces PE files)
- An exported symbol that shells can check for to determine whether to wait for the attached process to exit
- An exported symbol that shells can check for in order to determine whether to wait for the attached process to exit
- relies on shells to update and check for this
- cracking an executable to look for symbols is probably the last thing shells want to do
- we could provide an API to determine whether to wait or return?

View File

@ -360,7 +360,7 @@ GUID GetNamespaceGuid(IDynamicProfileGenerator& generator);
GUID GetGuidForName(IDynamicProfileGenerator& generator, std::wstring& name);
```
The generator does not _need_ to use `GetGuidForName` to generate guids for it's
The generator does not _need_ to use `GetGuidForName` to generate guids for its
profiles. If the generator can determine another way to generate stable GUIDs
for its profiles, it's free to use whatever method it wants. `GetGuidForName` is
provided as a convenience.

View File

@ -101,8 +101,8 @@ The scopes would work as follows:
this tab.
- **TODO!: FOR DISCUSSION**: Should this disable the tab's
"broadcastToAllPanes" setting? Or should it leave that alone?
* `"disableBroadcastInput"`: Set the global setting to false, the tab's setting
to false, and clear the set of panes being broadcasted to for this tab.
* `"disableBroadcastInput"`: For this tab, set the global setting to false,
the tab's setting to false, and clear the set of panes being broadcasted.
- **TODO!** This could also just be `"action": "toggleBroadcastInput",
"scope": "none"`
@ -161,7 +161,7 @@ As far as actions, we're looking at something like:
from the broadcast set. Otherwise, add all the panes from this tab to the
broadcast set.
* **D** toggle sending input to the current pane
* If this pane is in the broadcast set, remove it. Otherwise add it.
* If this pane is in the broadcast set, remove it. Otherwise, add it.
This seems to break down into the following actions:
```json

View File

@ -13,7 +13,7 @@ A significant amount of code is shared between Conhost and Windows Terminal to c
### Internal Partners
There are many first-party command-line applications on Windows. The following are a few examples of those that are regularly updated:
- [**GitHub CLI**](https://cli.github.com/): a tool that can be used to query and interact with GitHub repos (open source)
- [**Winget**](https://github.com/microsoft/winget-cli): a tool to install applications and other packages
- [**WinGet**](https://github.com/microsoft/winget-cli): a tool to install applications and other packages
- [**PSReadLine**](https://github.com/PowerShell/PSReadLine): a PowerShell module that enhances the input line experience
- [**Windows Subsystem for Linux (WSL)**](https://learn.microsoft.com/en-us/windows/wsl/): a tool to manage and run GNU/Linux environments without a traditional virtual machine
- [**PowerShell**](https://github.com/PowerShell/PowerShell): a cross-platform command-line shell (open source)

View File

@ -32,7 +32,7 @@
BasedOn="{StaticResource TitleBarButtonStyle}"
TargetType="{x:Type Button}">
<Setter Property="Content" Value="&#xE10A;" />
<!-- Remove the default Button template's Triggers, otherwise they'll override our trigger below. -->
<!-- Remove the default Button template's Triggers; otherwise, they'll override our trigger below. -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">

View File

@ -2969,7 +2969,7 @@ void TextBuffer::_SerializeRow(const ROW& row, const til::CoordType startX, cons
// parameter and we'll calculate the position of the _end_ of those rows in
// the new buffer. The rows's new value is placed back into this parameter.
// Return Value:
// - S_OK if we successfully copied the contents to the new buffer, otherwise an appropriate HRESULT.
// - S_OK if we successfully copied the contents to the new buffer; otherwise, an appropriate HRESULT.
void TextBuffer::Reflow(TextBuffer& oldBuffer, TextBuffer& newBuffer, const Viewport* lastCharacterViewport, PositionInformation* positionInfo)
{
const auto& oldCursor = oldBuffer.GetCursor();

View File

@ -573,7 +573,7 @@ namespace
TestCase{
// This triggers the cursor being walked forward w/ newlines to maintain
// distance from the last char in the buffer
L"SBCS, cursor at end of buffer, otherwise same as previous test",
L"SBCS, cursor at end of buffer; otherwise, same as previous test",
{
TestBuffer{
{ 6, 5 },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 787 B

View File

@ -7,6 +7,7 @@
<ProjectName>elevate-shim</ProjectName>
<TargetName>elevate-shim</TargetName>
<ConfigurationType>Application</ConfigurationType>
<VersionInfoFileDescription>Windows Terminal Administrator Launch Helper</VersionInfoFileDescription>
</PropertyGroup>
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />

View File

@ -2,8 +2,8 @@
// Licensed under the MIT license.
#include "pch.h"
#include "../TerminalApp/CommandLinePaletteItem.h"
#include "../TerminalApp/CommandPalette.h"
#include "../TerminalApp/BasePaletteItem.h"
#include "CppWinrtTailored.h"
using namespace Microsoft::Console;
@ -15,6 +15,20 @@ using namespace winrt::Microsoft::Terminal::Control;
namespace TerminalAppLocalTests
{
struct StringPaletteItem : winrt::implements<StringPaletteItem, winrt::TerminalApp::IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>, winrt::TerminalApp::implementation::BasePaletteItem<StringPaletteItem, winrt::TerminalApp::PaletteItemType::CommandLine>
{
StringPaletteItem(std::wstring_view value) :
_value{ value } {}
winrt::hstring Name() { return _value; }
winrt::hstring Subtitle() { return {}; }
winrt::hstring KeyChordText() { return {}; }
winrt::hstring Icon() { return {}; }
private:
winrt::hstring _value;
};
class FilteredCommandTests
{
BEGIN_TEST_CLASS(FilteredCommandTests)
@ -28,81 +42,81 @@ namespace TerminalAppLocalTests
TEST_METHOD(VerifyCompareIgnoreCase);
};
static void _verifySegment(auto&& segments, uint32_t index, uint64_t start, uint64_t end)
{
const auto& segment{ segments.GetAt(index) };
VERIFY_ARE_EQUAL(segment.Start, start, NoThrowString().Format(L"segment %zu", index));
VERIFY_ARE_EQUAL(segment.End, end, NoThrowString().Format(L"segment %zu", index));
}
void FilteredCommandTests::VerifyHighlighting()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
const WEX::TestExecution::DisableVerifyExceptions disableExceptionsScope;
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
{
Log::Comment(L"Testing command name segmentation with no filter");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
auto segments = filteredCommand->_computeHighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 1u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
const auto segments = filteredCommand->NameHighlights();
VERIFY_IS_NULL(segments); // No matches = no segments
}
{
Log::Comment(L"Testing command name segmentation with empty filter");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"";
auto segments = filteredCommand->_computeHighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 1u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"")));
const auto segments = filteredCommand->NameHighlights();
VERIFY_IS_NULL(segments); // No matches = no segments
}
{
Log::Comment(L"Testing command name segmentation with filter equal to the string");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"AAAAAABBBBBBCCC";
auto segments = filteredCommand->_computeHighlightedName().Segments();
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"AAAAAABBBBBBCCC")));
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 1u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
_verifySegment(segments, 0, 0, 14); // one segment for the entire string
}
{
Log::Comment(L"Testing command name segmentation with filter with first character matching");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"A";
auto segments = filteredCommand->_computeHighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 2u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"A");
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(1).IsHighlighted());
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"A")));
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 1u); // only one bold segment
_verifySegment(segments, 0, 0, 0); // it only covers the first character
}
{
Log::Comment(L"Testing command name segmentation with filter with other case");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"a";
auto segments = filteredCommand->_computeHighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 2u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"A");
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(1).IsHighlighted());
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"a")));
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 1u); // only one bold segment
_verifySegment(segments, 0, 0, 0); // it only covers the first character
}
{
Log::Comment(L"Testing command name segmentation with filter matching several characters");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"ab";
auto segments = filteredCommand->_computeHighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 4u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"A");
VERIFY_IS_TRUE(segments.GetAt(0).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(1).TextSegment(), L"AAAAA");
VERIFY_IS_FALSE(segments.GetAt(1).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(2).TextSegment(), L"B");
VERIFY_IS_TRUE(segments.GetAt(2).IsHighlighted());
VERIFY_ARE_EQUAL(segments.GetAt(3).TextSegment(), L"BBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(3).IsHighlighted());
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"ab")));
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 1u); // one bold segment
_verifySegment(segments, 0, 5, 6); // middle 'ab'
}
{
Log::Comment(L"Testing command name segmentation with filter matching several regions");
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"abcc")));
const auto segments = filteredCommand->NameHighlights();
VERIFY_ARE_EQUAL(segments.Size(), 2u); // two bold segments
_verifySegment(segments, 0, 5, 6); // middle 'ab'
_verifySegment(segments, 1, 12, 13); // start of 'cc'
}
{
Log::Comment(L"Testing command name segmentation with non matching filter");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"abcd";
auto segments = filteredCommand->_computeHighlightedName().Segments();
VERIFY_ARE_EQUAL(segments.Size(), 1u);
VERIFY_ARE_EQUAL(segments.GetAt(0).TextSegment(), L"AAAAAABBBBBBCCC");
VERIFY_IS_FALSE(segments.GetAt(0).IsHighlighted());
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"abcd")));
const auto segments = filteredCommand->NameHighlights();
VERIFY_IS_NULL(segments); // No matches = no segments
}
});
@ -112,54 +126,38 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyWeight()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
{
Log::Comment(L"Testing weight of command with no filter");
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
auto weight = filteredCommand->_computeWeight();
VERIFY_ARE_EQUAL(weight, 0);
}
const auto weigh = [&](const wchar_t* str) {
std::shared_ptr<fzf::matcher::Pattern> pattern;
if (str)
{
Log::Comment(L"Testing weight of command with empty filter");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"";
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
auto weight = filteredCommand->_computeWeight();
VERIFY_ARE_EQUAL(weight, 0);
}
{
Log::Comment(L"Testing weight of command with filter equal to the string");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"AAAAAABBBBBBCCC";
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
auto weight = filteredCommand->_computeWeight();
VERIFY_ARE_EQUAL(weight, 30); // 1 point for the first char and 2 points for the 14 consequent ones + 1 point for the beginning of the word
}
{
Log::Comment(L"Testing weight of command with filter with first character matching");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"A";
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
auto weight = filteredCommand->_computeWeight();
VERIFY_ARE_EQUAL(weight, 2); // 1 point for the first char match + 1 point for the beginning of the word
}
{
Log::Comment(L"Testing weight of command with filter with other case");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"a";
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
auto weight = filteredCommand->_computeWeight();
VERIFY_ARE_EQUAL(weight, 2); // 1 point for the first char match + 1 point for the beginning of the word
}
{
Log::Comment(L"Testing weight of command with filter matching several characters");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"ab";
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
auto weight = filteredCommand->_computeWeight();
VERIFY_ARE_EQUAL(weight, 3); // 1 point for the first char match + 1 point for the beginning of the word + 1 point for the match of "b"
pattern = std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(str));
}
filteredCommand->UpdateFilter(std::move(pattern));
return filteredCommand->Weight();
};
const auto null = weigh(nullptr);
const auto empty = weigh(L"");
const auto full = weigh(L"AAAAAABBBBBBCCC");
const auto firstChar = weigh(L"A");
const auto otherCase = weigh(L"a");
const auto severalChars = weigh(L"ab");
VERIFY_ARE_EQUAL(null, 0);
VERIFY_ARE_EQUAL(empty, 0);
VERIFY_IS_GREATER_THAN(full, 100);
VERIFY_IS_GREATER_THAN(firstChar, 0);
VERIFY_IS_LESS_THAN(firstChar, full);
VERIFY_IS_GREATER_THAN(otherCase, 0);
VERIFY_IS_LESS_THAN(otherCase, full);
VERIFY_IS_GREATER_THAN(severalChars, otherCase);
VERIFY_IS_LESS_THAN(severalChars, full);
});
VERIFY_SUCCEEDED(result);
@ -168,8 +166,8 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyCompare()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem2{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"BBBBBCCC") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"AAAAAABBBBBBCCC") };
const auto paletteItem2{ winrt::make<StringPaletteItem>(L"BBBBBCCC") };
{
Log::Comment(L"Testing comparison of commands with no filter");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
@ -181,14 +179,10 @@ namespace TerminalAppLocalTests
{
Log::Comment(L"Testing comparison of commands with empty filter");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"";
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
filteredCommand->_Weight = filteredCommand->_computeWeight();
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"")));
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);
filteredCommand2->_Filter = L"";
filteredCommand2->_HighlightedName = filteredCommand2->_computeHighlightedName();
filteredCommand2->_Weight = filteredCommand2->_computeWeight();
filteredCommand2->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"")));
VERIFY_ARE_EQUAL(filteredCommand->Weight(), filteredCommand2->Weight());
VERIFY_IS_TRUE(winrt::TerminalApp::implementation::FilteredCommand::Compare(*filteredCommand, *filteredCommand2));
@ -196,16 +190,12 @@ namespace TerminalAppLocalTests
{
Log::Comment(L"Testing comparison of commands with different weights");
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
filteredCommand->_Filter = L"B";
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
filteredCommand->_Weight = filteredCommand->_computeWeight();
filteredCommand->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"B")));
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);
filteredCommand2->_Filter = L"B";
filteredCommand2->_HighlightedName = filteredCommand2->_computeHighlightedName();
filteredCommand2->_Weight = filteredCommand2->_computeWeight();
filteredCommand2->UpdateFilter(std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(L"B")));
VERIFY_IS_TRUE(filteredCommand->Weight() < filteredCommand2->Weight()); // Second command gets more points due to the beginning of the word
VERIFY_IS_LESS_THAN(filteredCommand->Weight(), filteredCommand2->Weight()); // Second command gets more points due to the beginning of the word
VERIFY_IS_FALSE(winrt::TerminalApp::implementation::FilteredCommand::Compare(*filteredCommand, *filteredCommand2));
}
});
@ -216,8 +206,8 @@ namespace TerminalAppLocalTests
void FilteredCommandTests::VerifyCompareIgnoreCase()
{
auto result = RunOnUIThread([]() {
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"a") };
const auto paletteItem2{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"B") };
const auto paletteItem{ winrt::make<StringPaletteItem>(L"a") };
const auto paletteItem2{ winrt::make<StringPaletteItem>(L"B") };
{
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);

View File

@ -8,7 +8,7 @@
#include "../TerminalApp/MinMaxCloseControl.h"
#include "../TerminalApp/TabRowControl.h"
#include "../TerminalApp/ShortcutActionDispatch.h"
#include "../TerminalApp/TerminalTab.h"
#include "../TerminalApp/Tab.h"
#include "../TerminalApp/CommandPalette.h"
#include "../TerminalApp/ContentManager.h"
#include "CppWinrtTailored.h"
@ -307,7 +307,7 @@ namespace TerminalAppLocalTests
// reliably in the unit tests.
Log::Comment(L"Ensure we set the first tab as the selected one.");
auto tab = page->_tabs.GetAt(0);
auto tabImpl = page->_GetTerminalTabImpl(tab);
auto tabImpl = page->_GetTabImpl(tab);
page->_tabView.SelectedItem(tabImpl->TabViewItem());
page->_UpdatedSelectedTab(tab);
});
@ -510,7 +510,7 @@ namespace TerminalAppLocalTests
result = RunOnUIThread([&page]() {
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(1, tab->GetLeafPaneCount());
});
VERIFY_SUCCEEDED(result);
@ -520,7 +520,7 @@ namespace TerminalAppLocalTests
page->_SplitPane(nullptr, SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, tab->GetLeafPaneCount());
});
VERIFY_SUCCEEDED(result);
@ -538,7 +538,7 @@ namespace TerminalAppLocalTests
page->_SplitPane(nullptr, SplitDirection::Automatic, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(3,
tab->GetLeafPaneCount(),
L"We should successfully duplicate a pane hosting a deleted profile.");
@ -706,7 +706,7 @@ namespace TerminalAppLocalTests
SplitPaneArgs args{ SplitType::Duplicate };
ActionEventArgs eventArgs{ args };
page->_HandleSplitPane(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
@ -717,7 +717,7 @@ namespace TerminalAppLocalTests
result = RunOnUIThread([&page]() {
ActionEventArgs eventArgs{};
page->_HandleTogglePaneZoom(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
@ -727,7 +727,7 @@ namespace TerminalAppLocalTests
result = RunOnUIThread([&page]() {
ActionEventArgs eventArgs{};
page->_HandleTogglePaneZoom(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
});
@ -744,7 +744,7 @@ namespace TerminalAppLocalTests
SplitPaneArgs args{ SplitType::Duplicate };
ActionEventArgs eventArgs{ args };
page->_HandleSplitPane(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
@ -758,7 +758,7 @@ namespace TerminalAppLocalTests
page->_HandleTogglePaneZoom(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
@ -772,7 +772,7 @@ namespace TerminalAppLocalTests
page->_HandleMoveFocus(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
@ -789,7 +789,7 @@ namespace TerminalAppLocalTests
SplitPaneArgs args{ SplitType::Duplicate };
ActionEventArgs eventArgs{ args };
page->_HandleSplitPane(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
@ -803,7 +803,7 @@ namespace TerminalAppLocalTests
page->_HandleTogglePaneZoom(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
@ -816,7 +816,7 @@ namespace TerminalAppLocalTests
page->_HandleClosePane(nullptr, eventArgs);
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_IS_FALSE(firstTab->IsZoomed());
});
VERIFY_SUCCEEDED(result);
@ -827,7 +827,7 @@ namespace TerminalAppLocalTests
Log::Comment(L"Check to ensure there's only one pane left.");
result = RunOnUIThread([&page]() {
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto firstTab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(1, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
});
@ -850,7 +850,7 @@ namespace TerminalAppLocalTests
uint32_t firstId = 0, secondId = 0, thirdId = 0, fourthId = 0;
TestOnUIThread([&]() {
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
firstId = tab->_activePane->Id().value();
// We start with 1 tab, split vertically to get
// -------------------
@ -876,7 +876,7 @@ namespace TerminalAppLocalTests
// | | |
// -------------------
page->_SplitPane(nullptr, SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
// Split again to make the 3rd tab
thirdId = tab->_activePane->Id().value();
});
@ -896,13 +896,13 @@ namespace TerminalAppLocalTests
// | | |
// -------------------
page->_SplitPane(nullptr, SplitDirection::Down, 0.5f, page->_MakePane(nullptr, page->_GetFocusedTab(), nullptr));
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
fourthId = tab->_activePane->Id().value();
});
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// just to be complete, make sure we actually have 4 different ids
VERIFY_ARE_NOT_EQUAL(firstId, fourthId);
@ -936,7 +936,7 @@ namespace TerminalAppLocalTests
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// Our currently focused pane should be `4`
VERIFY_ARE_EQUAL(fourthId, tab->_activePane->Id().value());
@ -967,7 +967,7 @@ namespace TerminalAppLocalTests
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// Our currently focused pane should be `4`
VERIFY_ARE_EQUAL(fourthId, tab->_activePane->Id().value());
@ -998,7 +998,7 @@ namespace TerminalAppLocalTests
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// Our currently focused pane should be `4`
VERIFY_ARE_EQUAL(fourthId, tab->_activePane->Id().value());
@ -1029,7 +1029,7 @@ namespace TerminalAppLocalTests
Sleep(250);
TestOnUIThread([&]() {
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
auto tab = page->_GetTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(4, tab->GetLeafPaneCount());
// Our currently focused pane should be `4`
VERIFY_ARE_EQUAL(fourthId, tab->_activePane->Id().value());
@ -1174,16 +1174,16 @@ namespace TerminalAppLocalTests
Log::Comment(L"give alphabetical names to all switch tab actions");
TestOnUIThread([&page]() {
page->_GetTerminalTabImpl(page->_tabs.GetAt(0))->Title(L"a");
page->_GetTabImpl(page->_tabs.GetAt(0))->Title(L"a");
});
TestOnUIThread([&page]() {
page->_GetTerminalTabImpl(page->_tabs.GetAt(1))->Title(L"b");
page->_GetTabImpl(page->_tabs.GetAt(1))->Title(L"b");
});
TestOnUIThread([&page]() {
page->_GetTerminalTabImpl(page->_tabs.GetAt(2))->Title(L"c");
page->_GetTabImpl(page->_tabs.GetAt(2))->Title(L"c");
});
TestOnUIThread([&page]() {
page->_GetTerminalTabImpl(page->_tabs.GetAt(3))->Title(L"d");
page->_GetTabImpl(page->_tabs.GetAt(3))->Title(L"d");
});
TestOnUIThread([&page]() {

View File

@ -21,7 +21,7 @@ static constexpr std::wstring_view VerbName{ L"WindowsTerminalOpenHere" };
// Arguments:
// - psiItemArray: a IShellItemArray which contains the item that's selected.
// Return Value:
// - S_OK if we successfully attempted to launch the Terminal, otherwise a
// - S_OK if we successfully attempted to launch the Terminal; otherwise, a
// failure from an earlier HRESULT.
HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
IBindCtx* /*pBindContext*/)

View File

@ -10,6 +10,7 @@
<SubSystem>Console</SubSystem>
<!-- suppress a bunch of Windows Universal properties from cppwinrt.props -->
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
<VersionInfoFileDescription>Windows Terminal Open Here Shell Extension</VersionInfoFileDescription>
</PropertyGroup>
<PropertyGroup Label="NuGet Dependencies">
<TerminalCppWinrt>true</TerminalCppWinrt>

View File

@ -28,18 +28,18 @@
</TextBlock>
<StackPanel Orientation="Vertical">
<StackPanel Padding="0,4,0,4"
<StackPanel Padding="0,16,0,16"
VerticalAlignment="Center"
Orientation="Horizontal"
Spacing="8"
Visibility="{x:Bind CheckingForUpdates, Mode=OneWay}">
<mux:ProgressRing Width="16"
Height="16"
IsActive="True"
IsIndeterminate="True" />
<TextBlock x:Uid="AboutDialog_CheckingForUpdatesLabel"
Padding="4,0,0,0" />
<TextBlock x:Uid="AboutDialog_CheckingForUpdatesLabel" />
</StackPanel>
<StackPanel Padding="0,4,0,4"
<StackPanel Padding="0,16,0,16"
VerticalAlignment="Center"
Orientation="Vertical"
Visibility="{x:Bind UpdatesAvailable, Mode=OneWay}">
@ -51,6 +51,8 @@
</StackPanel>
</StackPanel>
<StackPanel Margin="-12,0,0,0"
Orientation="Vertical">
<HyperlinkButton x:Uid="AboutDialog_SourceCodeLink"
NavigateUri="https://go.microsoft.com/fwlink/?linkid=2203152" />
<HyperlinkButton x:Uid="AboutDialog_DocumentationLink"
@ -62,4 +64,5 @@
<HyperlinkButton x:Uid="AboutDialog_ThirdPartyNoticesLink"
Click="_ThirdPartyNoticesOnClick" />
</StackPanel>
</StackPanel>
</ContentDialog>

View File

@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ActionPaletteItem.h"
#include <LibraryResources.h>
#include "ActionPaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
ActionPaletteItem::ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText) :
_Command(command)
{
Name(command.Name());
KeyChordText(keyChordText);
Icon(command.IconPath());
}
}

View File

@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.h"
#include "ActionPaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct ActionPaletteItem : ActionPaletteItemT<ActionPaletteItem, PaletteItem>
{
ActionPaletteItem() = default;
ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText);
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::Command, Command, nullptr);
private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _commandChangedRevoker;
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(ActionPaletteItem);
}

View File

@ -1,14 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "PaletteItem.idl";
namespace TerminalApp
{
[default_interface] runtimeclass ActionPaletteItem : PaletteItem
{
ActionPaletteItem(Microsoft.Terminal.Settings.Model.Command command, String keyChordText);
Microsoft.Terminal.Settings.Model.Command Command { get; };
}
}

View File

@ -243,6 +243,8 @@
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
<ResourceDictionary Source="ms-resource:///Files/TerminalApp/HighlightedTextControlStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

View File

@ -41,13 +41,13 @@ namespace winrt::TerminalApp::implementation
}
return _GetActiveControl();
}
winrt::com_ptr<TerminalTab> TerminalPage::_senderOrFocusedTab(const IInspectable& sender)
winrt::com_ptr<Tab> TerminalPage::_senderOrFocusedTab(const IInspectable& sender)
{
if (sender)
{
if (auto tab{ sender.try_as<TerminalApp::TerminalTab>() })
if (auto tab = sender.try_as<TerminalApp::Tab>())
{
return _GetTerminalTabImpl(tab);
return _GetTabImpl(tab);
}
}
return _GetFocusedTabImpl();
@ -193,17 +193,17 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleCloseOtherPanes(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& terminalTab{ _senderOrFocusedTab(sender) })
if (const auto& activeTab{ _senderOrFocusedTab(sender) })
{
const auto activePane = terminalTab->GetActivePane();
if (terminalTab->GetRootPane() != activePane)
const auto activePane = activeTab->GetActivePane();
if (activeTab->GetRootPane() != activePane)
{
_UnZoomIfNeeded();
// Accumulate list of all unfocused leaf panes, ignore read-only panes
std::vector<uint32_t> unfocusedPaneIds;
const auto activePaneId = activePane->Id();
terminalTab->GetRootPane()->WalkTree([&](auto&& p) {
activeTab->GetRootPane()->WalkTree([&](auto&& p) {
const auto id = p->Id();
if (id.has_value() && id != activePaneId && !p->ContainsReadOnly())
{
@ -215,7 +215,7 @@ namespace winrt::TerminalApp::implementation
{
// Start by removing the panes that were least recently added
sort(begin(unfocusedPaneIds), end(unfocusedPaneIds), std::less<uint32_t>());
_ClosePanes(terminalTab->get_weak(), std::move(unfocusedPaneIds));
_ClosePanes(activeTab->get_weak(), std::move(unfocusedPaneIds));
args.Handled(true);
return;
}
@ -281,9 +281,9 @@ namespace winrt::TerminalApp::implementation
const auto& duplicateFromTab{ realArgs.SplitMode() == SplitType::Duplicate ? _GetFocusedTab() : nullptr };
const auto& terminalTab{ _senderOrFocusedTab(sender) };
const auto& activeTab{ _senderOrFocusedTab(sender) };
_SplitPane(terminalTab,
_SplitPane(activeTab,
realArgs.SplitDirection(),
// This is safe, we're already filtering so the value is (0, 1)
realArgs.SplitSize(),
@ -302,14 +302,14 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleTogglePaneZoom(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto terminalTab{ _senderOrFocusedTab(sender) })
if (const auto activeTab{ _senderOrFocusedTab(sender) })
{
// Don't do anything if there's only one pane. It's already zoomed.
if (terminalTab->GetLeafPaneCount() > 1)
if (activeTab->GetLeafPaneCount() > 1)
{
// Togging the zoom on the tab will cause the tab to inform us of
// the new root Content for this tab.
terminalTab->ToggleZoom();
activeTab->ToggleZoom();
}
}
@ -517,7 +517,7 @@ namespace winrt::TerminalApp::implementation
else
{
// Mark as handled only when the move succeeded (e.g. when there
// is a pane to move to), otherwise mark as unhandled so the
// is a pane to move to); otherwise, mark as unhandled so the
// keychord can propagate to the terminal (GH#6129)
const auto moveSucceeded = _MoveFocus(realArgs.FocusDirection());
args.Handled(moveSucceeded);
@ -548,7 +548,9 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = args.ActionArgs().try_as<CopyTextArgs>())
{
const auto handled = _CopyText(realArgs.DismissSelection(), realArgs.SingleLine(), realArgs.WithControlSequences(), realArgs.CopyFormatting());
const auto copyFormatting = realArgs.CopyFormatting();
const auto format = copyFormatting ? copyFormatting.Value() : _settings.GlobalSettings().CopyFormatting();
const auto handled = _CopyText(realArgs.DismissSelection(), realArgs.SingleLine(), realArgs.WithControlSequences(), format);
args.Handled(handled);
}
}
@ -756,7 +758,7 @@ namespace winrt::TerminalApp::implementation
if (!actions.empty())
{
actionArgs.Handled(true);
ProcessStartupActions(std::move(actions), false);
ProcessStartupActions(std::move(actions));
}
}
}
@ -783,7 +785,7 @@ namespace winrt::TerminalApp::implementation
}
// Since _RemoveTabs is asynchronous, create a snapshot of the tabs we want to remove
std::vector<winrt::TerminalApp::TabBase> tabsToRemove;
std::vector<winrt::TerminalApp::Tab> tabsToRemove;
if (index > 0)
{
std::copy(begin(_tabs), begin(_tabs) + index, std::back_inserter(tabsToRemove));
@ -822,7 +824,7 @@ namespace winrt::TerminalApp::implementation
}
// Since _RemoveTabs is asynchronous, create a snapshot of the tabs we want to remove
std::vector<winrt::TerminalApp::TabBase> tabsToRemove;
std::vector<winrt::TerminalApp::Tab> tabsToRemove;
std::copy(begin(_tabs) + index + 1, end(_tabs), std::back_inserter(tabsToRemove));
_RemoveTabs(tabsToRemove);
@ -1559,7 +1561,6 @@ namespace winrt::TerminalApp::implementation
activeTab->ToggleBroadcastInput();
args.Handled(true);
}
// If the focused tab wasn't a TerminalTab, then leave handled=false
}
void TerminalPage::_HandleRestartConnection(const IInspectable& sender,

View File

@ -961,18 +961,6 @@ std::vector<ActionAndArgs>& AppCommandlineArgs::GetStartupActions()
return _startupActions;
}
// Method Description:
// - Returns whether we should start listening for inbound PTY connections
// coming from the operating system default application feature.
// Arguments:
// - <none>
// Return Value:
// - True if the listener should be started. False otherwise.
bool AppCommandlineArgs::IsHandoffListener() const noexcept
{
return _isHandoffListener;
}
// Method Description:
// - Get the string of text that should be displayed to the user on exit. This
// is usually helpful for cases where the user entered some sort of invalid
@ -1014,11 +1002,6 @@ bool AppCommandlineArgs::ShouldExitEarly() const noexcept
// Return Value:
// - <none>
void AppCommandlineArgs::ValidateStartupCommands()
{
// Only check over the actions list for the potential to add a new-tab
// command if we are not starting for the purposes of receiving an inbound
// handoff connection from the operating system.
if (!_isHandoffListener)
{
// If we only have a single x-save command, then set our target to the
// current terminal window. This will prevent us from spawning a new
@ -1044,7 +1027,6 @@ void AppCommandlineArgs::ValidateStartupCommands()
_startupActions.insert(_startupActions.begin(), 1, newTabAction);
}
}
}
std::optional<uint32_t> AppCommandlineArgs::GetPersistedLayoutIdx() const noexcept
{
return _loadPersistedLayoutIdx >= 0 ?
@ -1082,14 +1064,10 @@ std::optional<til::size> AppCommandlineArgs::GetSize() const noexcept
// - 0 if the commandline was successfully parsed
int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring> args)
{
for (const auto& arg : args)
if (args.size() == 2 && args[1] == L"-Embedding")
{
if (arg == L"-Embedding")
{
_isHandoffListener = true;
return 0;
}
}
auto commands = ::TerminalApp::AppCommandlineArgs::BuildCommands(args);
@ -1195,7 +1173,6 @@ void AppCommandlineArgs::FullResetState()
_startupActions.clear();
_exitMessage = "";
_shouldExitEarly = false;
_isHandoffListener = false;
_windowTarget = {};
}

View File

@ -35,7 +35,6 @@ public:
void ValidateStartupCommands();
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs>& GetStartupActions();
bool IsHandoffListener() const noexcept;
const std::string& GetExitMessage() const noexcept;
bool ShouldExitEarly() const noexcept;
@ -132,7 +131,6 @@ private:
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchPosition> _position{ std::nullopt };
std::optional<til::size> _size{ std::nullopt };
bool _isHandoffListener{ false };
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
std::string _exitMessage;
bool _shouldExitEarly{ false };

View File

@ -135,7 +135,14 @@ namespace winrt::TerminalApp::implementation
_isElevated = ::Microsoft::Console::Utils::IsRunningElevated();
_canDragDrop = ::Microsoft::Console::Utils::CanUwpDragDrop();
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
_reloadSettings = std::make_shared<ThrottledFunc<>>(
DispatcherQueue::GetForCurrentThread(),
til::throttled_func_options{
.delay = std::chrono::milliseconds{ 100 },
.debounce = true,
.trailing = true,
},
[weakSelf = get_weak()]() {
if (auto self{ weakSelf.get() })
{
self->ReloadSettings();
@ -194,7 +201,7 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Attempt to load the settings. If we fail for any reason, returns an error.
// Return Value:
// - S_OK if we successfully parsed the settings, otherwise an appropriate HRESULT.
// - S_OK if we successfully parsed the settings; otherwise, an appropriate HRESULT.
[[nodiscard]] HRESULT AppLogic::_TryLoadSettings() noexcept
{
auto hr = E_FAIL;
@ -392,7 +399,7 @@ namespace winrt::TerminalApp::implementation
auto ev = winrt::make_self<SettingsLoadEventArgs>(true,
static_cast<uint64_t>(_settingsLoadedResult),
_settingsLoadExceptionText,
warnings,
warnings.GetView(),
_settings);
SettingsChanged.raise(*this, *ev);
return;
@ -424,7 +431,7 @@ namespace winrt::TerminalApp::implementation
auto ev = winrt::make_self<SettingsLoadEventArgs>(!initialLoad,
_settingsLoadedResult,
_settingsLoadExceptionText,
warnings,
warnings.GetView(),
_settings);
SettingsChanged.raise(*this, *ev);
}
@ -491,7 +498,7 @@ namespace winrt::TerminalApp::implementation
auto ev = winrt::make_self<SettingsLoadEventArgs>(false,
_settingsLoadedResult,
_settingsLoadExceptionText,
warnings,
warnings.GetView(),
_settings);
auto window = winrt::make_self<implementation::TerminalWindow>(*ev, _contentManager);

View File

@ -64,7 +64,7 @@ namespace winrt::TerminalApp::implementation
bool _hasSettingsStartupActions{ false };
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
std::shared_ptr<ThrottledFunc<>> _reloadSettings;
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings{};

View File

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
namespace winrt::TerminalApp::implementation
{
template<typename T, winrt::TerminalApp::PaletteItemType Ty>
struct BasePaletteItem
{
public:
winrt::TerminalApp::PaletteItemType Type() { return Ty; }
Windows::UI::Xaml::Controls::IconElement ResolvedIcon()
{
const auto icon{ static_cast<T*>(this)->Icon() };
if (!icon.empty())
{
const auto resolvedIcon{ Microsoft::Terminal::UI::IconPathConverter::IconWUX(icon) };
resolvedIcon.Width(16);
resolvedIcon.Height(16);
return resolvedIcon;
}
return nullptr;
}
til::property_changed_event PropertyChanged;
protected:
void BaseRaisePropertyChanged(wil::zwstring_view property)
{
PropertyChanged.raise(*static_cast<T*>(this), winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs{ property });
}
void InvalidateResolvedIcon()
{
BaseRaisePropertyChanged(L"ResolvedIcon");
}
};
}

View File

@ -1,267 +0,0 @@
#include "ColorHelper.h"
using namespace winrt::TerminalApp;
// Method Description:
// Determines whether or not a given color is light
// Arguments:
// - color: this color is going to be examined whether it
// is light or not
// Return Value:
// - true of light, false if dark
bool ColorHelper::IsBrightColor(const winrt::Windows::UI::Color& color)
{
// https://www.w3.org/TR/AERT#color-contrast
auto brightness = (color.R * 299 + color.G * 587 + color.B * 114) / 1000.f;
return brightness > 128.f;
}
// Method Description:
// Converts a rgb color to an hsl one
// Arguments:
// - color: the rgb color, which is going to be converted
// Return Value:
// - a hsl color with the following ranges
// - H: [0.f -360.f]
// - L: [0.f - 1.f] (rounded to the third decimal place)
// - S: [0.f - 1.f] (rounded to the third decimal place)
HSL ColorHelper::RgbToHsl(const winrt::Windows::UI::Color& color)
{
// https://www.rapidtables.com/convert/color/rgb-to-hsl.html
auto epsilon = std::numeric_limits<float>::epsilon();
auto r = color.R / 255.f;
auto g = color.G / 255.f;
auto b = color.B / 255.f;
auto max = std::max(r, std::max(g, b));
auto min = std::min(r, std::min(g, b));
auto delta = max - min;
auto h = 0.f;
auto s = 0.f;
auto l = (max + min) / 2;
if (delta < epsilon || max < epsilon) /* delta == 0 || max == 0*/
{
l = std::roundf(l * 1000) / 1000;
return HSL{ h, s, l };
}
s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
if (max - r < epsilon) // max == r
{
h = (g - b) / delta + (g < b ? 6 : 0);
}
else if (max - g < epsilon) // max == g
{
h = (b - r) / delta + 2;
}
else if (max - b < epsilon) // max == b
{
h = (r - g) / delta + 4;
}
// three decimal places after the comma ought
// to be enough for everybody - Bill Gates, 1981
auto finalH = std::roundf(h * 60);
auto finalS = std::roundf(s * 1000) / 1000;
auto finalL = std::roundf(l * 1000) / 1000;
return HSL{ finalH, finalS, finalL };
}
// Method Description:
// Converts a hsl color to rgb one
// Arguments:
// - color: the hsl color, which is going to be converted
// Return Value:
// - the rgb color (r,g,b - [0, 255] range)
winrt::Windows::UI::Color ColorHelper::HslToRgb(const HSL& color)
{
auto epsilon = std::numeric_limits<float>::epsilon();
auto h = (color.H - 1.f > epsilon) ? color.H / 360.f : color.H;
auto s = (color.S - 1.f > epsilon) ? color.S / 100.f : color.S;
auto l = (color.L - 1.f > epsilon) ? color.L / 100.f : color.L;
auto r = l;
auto g = l;
auto b = l;
if (s > epsilon)
{
auto q = l < 0.5 ? l * (1 + s) : l + s - l * s;
auto p = 2 * l - q;
r = HueToRgb(p, q, h + 1.f / 3.f);
g = HueToRgb(p, q, h);
b = HueToRgb(p, q, h - 1.f / 3.f);
}
auto finalR = static_cast<uint8_t>(std::roundf(r * 255));
auto finalG = static_cast<uint8_t>(std::roundf(g * 255));
auto finalB = static_cast<uint8_t>(std::roundf(b * 255));
uint8_t finalA = 255; //opaque
return winrt::Windows::UI::ColorHelper::FromArgb(finalA, finalR, finalG, finalB);
}
float ColorHelper::HueToRgb(float p, float q, float t)
{
auto epsilon = std::numeric_limits<float>::epsilon();
if (t < 0)
t += 1;
if (t > 1)
t -= 1;
if (t - (1.f / 6.f) < epsilon)
return p + (q - p) * 6 * t;
if (t - .5f < epsilon)
return q;
if (t - 2.f / 3.f < epsilon)
return p + (q - p) * (2.f / 3.f - t) * 6;
return p;
}
// Method Description:
// Lightens a color by a given amount
// Arguments:
// - color: the color which is going to be lightened
// - amount: the lighten amount (0-100)
// Return Value:
// - the lightened color in RGB format
winrt::Windows::UI::Color ColorHelper::Lighten(const winrt::Windows::UI::Color& color, float amount /* = 10.f*/)
{
auto hsl = RgbToHsl(color);
hsl.L += amount / 100;
hsl.L = std::clamp(hsl.L, 0.f, 1.f);
return HslToRgb(hsl);
}
// Method Description:
// Darkens a color by a given amount
// Arguments:
// - color: the color which is going to be darkened
// - amount: the darken amount (0-100)
// Return Value:
// - the darkened color in RGB format
winrt::Windows::UI::Color ColorHelper::Darken(const winrt::Windows::UI::Color& color, float amount /* = 10.f*/)
{
auto hsl = RgbToHsl(color);
hsl.L -= amount / 100;
hsl.L = std::clamp(hsl.L, 0.f, 1.f);
return HslToRgb(hsl);
}
// Method Description:
// Gets an accent color to a given color. Basically, generates
// 16 shades of the color and finds the first which has a good
// contrast according to https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Readability ratio of 3.5 seems to look quite nicely
// Arguments:
// - color: the color for which we need an accent
// Return Value:
// - the accent color in RGB format
winrt::Windows::UI::Color ColorHelper::GetAccentColor(const winrt::Windows::UI::Color& color)
{
auto accentColor = RgbToHsl(color);
if (accentColor.S < 0.15)
{
accentColor.S = 0.15f;
}
constexpr auto shadeCount = 16;
constexpr auto shadeStep = 1.f / shadeCount;
auto shades = std::map<float, HSL>();
for (auto i = 0; i < 15; i++)
{
auto shade = HSL{ accentColor.H, accentColor.S, i * shadeStep };
auto contrast = GetReadability(shade, accentColor);
shades.insert(std::make_pair(contrast, shade));
}
// 3f is quite nice if the whole non-client area is painted
constexpr auto readability = 1.75f;
for (auto shade : shades)
{
if (shade.first >= readability)
{
return HslToRgb(shade.second);
}
}
return HslToRgb(shades.end()->second);
}
// Method Description:
// Gets the readability of two colors according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Arguments:
// - firstColor: the first color for the readability check (hsl)
// - secondColor: the second color for the readability check (hsl)
// Return Value:
// - the readability of the colors according to (WCAG Version 2)
float ColorHelper::GetReadability(const HSL& first, const HSL& second)
{
return GetReadability(HslToRgb(first), HslToRgb(second));
}
// Method Description:
// Gets the readability of two colors according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef (WCAG Version 2)
// Arguments:
// - firstColor: the first color for the readability check (rgb)
// - secondColor: the second color for the readability check (rgb)
// Return Value:
// - the readability of the colors according to (WCAG Version 2)
float ColorHelper::GetReadability(const winrt::Windows::UI::Color& first, const winrt::Windows::UI::Color& second)
{
auto l1 = GetLuminance(first);
auto l2 = GetLuminance(second);
return (std::max(l1, l2) + 0.05f) / std::min(l1, l2) + 0.05f;
}
// Method Description:
// Calculates the luminance of a given color according to
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
// Arguments:
// - color: its luminance is going to be calculated
// Return Value:
// - the luminance of the color
float ColorHelper::GetLuminance(const winrt::Windows::UI::Color& color)
{
auto epsilon = std::numeric_limits<float>::epsilon();
float R, G, B;
auto RsRGB = color.R / 255.f;
auto GsRGB = color.G / 255.f;
auto BsRGB = color.B / 255.f;
if (RsRGB - 0.03928f <= epsilon)
{
R = RsRGB / 12.92f;
}
else
{
R = std::pow(((RsRGB + 0.055f) / 1.055f), 2.4f);
}
if (GsRGB - 0.03928f <= epsilon)
{
G = GsRGB / 12.92f;
}
else
{
G = std::pow(((GsRGB + 0.055f) / 1.055f), 2.4f);
}
if (BsRGB - 0.03928f <= epsilon)
{
B = BsRGB / 12.92f;
}
else
{
B = std::pow(((BsRGB + 0.055f) / 1.055f), 2.4f);
}
auto luminance = (0.2126f * R) + (0.7152f * G) + (0.0722f * B);
return std::roundf(luminance * 10000) / 10000.f;
}

View File

@ -1,31 +0,0 @@
#pragma once
#include <winrt/Windows.UI.h>
namespace winrt::TerminalApp
{
class HSL
{
public:
float H;
float S;
float L;
};
class ColorHelper
{
public:
static bool IsBrightColor(const Windows::UI::Color& color);
static HSL RgbToHsl(const Windows::UI::Color& color);
static Windows::UI::Color HslToRgb(const HSL& color);
static Windows::UI::Color Lighten(const Windows::UI::Color& color, float amount = 10.f);
static Windows::UI::Color Darken(const Windows::UI::Color& color, float amount = 10.f);
static Windows::UI::Color GetAccentColor(const Windows::UI::Color& color);
static float GetLuminance(const Windows::UI::Color& color);
static float GetReadability(const Windows::UI::Color& first, const Windows::UI::Color& second);
static float GetReadability(const HSL& first, const HSL& second);
private:
static float HueToRgb(float p, float q, float t);
};
}

View File

@ -1,26 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "CommandLinePaletteItem.h"
#include <LibraryResources.h>
#include "CommandLinePaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
CommandLinePaletteItem::CommandLinePaletteItem(const winrt::hstring& commandLine) :
_CommandLine(commandLine)
{
Name(commandLine);
}
}

View File

@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.h"
#include "CommandLinePaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct CommandLinePaletteItem : CommandLinePaletteItemT<CommandLinePaletteItem, PaletteItem>
{
CommandLinePaletteItem() = default;
CommandLinePaletteItem(const winrt::hstring& commandLine);
WINRT_PROPERTY(winrt::hstring, CommandLine);
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(CommandLinePaletteItem);
}

View File

@ -1,12 +0,0 @@
import "PaletteItem.idl";
import "TabBase.idl";
namespace TerminalApp
{
[default_interface] runtimeclass CommandLinePaletteItem : PaletteItem
{
CommandLinePaletteItem(String commandLine);
String CommandLine { get; };
}
}

View File

@ -2,10 +2,8 @@
// Licensed under the MIT license.
#include "pch.h"
#include "ActionPaletteItem.h"
#include "TabPaletteItem.h"
#include "CommandLinePaletteItem.h"
#include "CommandPalette.h"
#include "CommandPaletteItems.h"
#include <LibraryResources.h>
#include "CommandPalette.g.cpp"
@ -233,9 +231,11 @@ namespace winrt::TerminalApp::implementation
}
else if (_currentMode == CommandPaletteMode::ActionMode && filteredCommand != nullptr)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
else if (_currentMode == CommandPaletteMode::CommandlineMode)
@ -338,7 +338,7 @@ namespace winrt::TerminalApp::implementation
}
else if (key == VirtualKey::Escape)
{
// Dismiss the palette if the text is empty, otherwise clear the
// Dismiss the palette if the text is empty; otherwise, clear the
// search string.
if (_searchBox().Text().empty())
{
@ -555,10 +555,11 @@ namespace winrt::TerminalApp::implementation
const auto enteredItem = listViewItem.Content();
if (const auto filteredCommand{ enteredItem.try_as<winrt::TerminalApp::FilteredCommand>() })
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
// immediately preview the hovered command
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
}
@ -589,9 +590,11 @@ namespace winrt::TerminalApp::implementation
{
if (_currentMode == CommandPaletteMode::ActionMode && filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
PreviewAction.raise(*this, actionPaletteItem.Command());
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
PreviewAction.raise(*this, actionPaletteItem->Command());
}
}
}
@ -617,7 +620,7 @@ namespace winrt::TerminalApp::implementation
const auto selectedCommand = selectedList.GetAt(0);
if (const auto filteredCmd = selectedCommand.try_as<TerminalApp::FilteredCommand>())
{
if (const auto paletteItem = filteredCmd.Item().try_as<TerminalApp::PaletteItem>())
if (const auto paletteItem = filteredCmd.Item())
{
automationPeer.RaiseNotificationEvent(
Automation::Peers::AutomationNotificationKind::ItemAdded,
@ -652,10 +655,13 @@ namespace winrt::TerminalApp::implementation
if (_nestedActionStack.Size() > 0)
{
const auto newPreviousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
const auto actionPaletteItem{ newPreviousAction.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() };
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
const auto item{ newPreviousAction.Item() };
if (item.Type() == PaletteItemType::Action)
{
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
ParentCommandName(actionPaletteItem->Command().Name());
_updateCurrentNestedCommands(actionPaletteItem->Command());
}
}
else
{
@ -757,16 +763,19 @@ namespace winrt::TerminalApp::implementation
}
else if (filteredCommand)
{
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Action)
{
if (actionPaletteItem.Command().HasNestedCommands())
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(item) };
auto command{ actionPaletteItem->Command() };
if (command.HasNestedCommands())
{
// If this Command had subcommands, then don't dispatch the
// action. Instead, display a new list of commands for the user
// to pick from.
_nestedActionStack.Append(filteredCommand);
ParentCommandName(actionPaletteItem.Command().Name());
_updateCurrentNestedCommands(actionPaletteItem.Command());
ParentCommandName(command.Name());
_updateCurrentNestedCommands(command);
_updateUIForStackChange();
}
@ -785,9 +794,9 @@ namespace winrt::TerminalApp::implementation
// But make an exception for the Toggle Command Palette action: we don't want the dispatch
// make the command palette - that was just closed - visible again.
// All other actions can just be dispatched.
if (actionPaletteItem.Command().ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
if (command.ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
{
DispatchCommandRequested.raise(*this, actionPaletteItem.Command());
DispatchCommandRequested.raise(*this, command);
}
TraceLoggingWrite(
@ -837,9 +846,11 @@ namespace winrt::TerminalApp::implementation
{
if (filteredCommand)
{
if (const auto tabPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::TabPaletteItem>() })
const auto item{ filteredCommand.Item() };
if (item.Type() == PaletteItemType::Tab)
{
if (const auto tab{ tabPaletteItem.Tab() })
const auto tabPaletteItem{ winrt::get_self<TabPaletteItem>(item) };
if (const auto tab{ tabPaletteItem->Tab() })
{
SwitchToTabRequested.raise(*this, tab);
}
@ -867,9 +878,11 @@ namespace winrt::TerminalApp::implementation
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
if (const auto commandLinePaletteItem{ filteredCommand.value().Item().try_as<winrt::TerminalApp::CommandLinePaletteItem>() })
const auto item{ filteredCommand->Item() };
if (item.Type() == PaletteItemType::CommandLine)
{
CommandLineExecutionRequested.raise(*this, commandLinePaletteItem.CommandLine());
const auto commandLinePaletteItem{ winrt::get_self<CommandLinePaletteItem>(item) };
CommandLineExecutionRequested.raise(*this, commandLinePaletteItem->CommandLine());
_close();
}
}
@ -1059,7 +1072,7 @@ namespace winrt::TerminalApp::implementation
// Return Value:
// - <none>
void CommandPalette::_bindTabs(
const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase>& source,
const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::Tab>& source,
const Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand>& target)
{
target.Clear();
@ -1071,7 +1084,7 @@ namespace winrt::TerminalApp::implementation
}
}
void CommandPalette::SetTabs(const Collections::IObservableVector<TabBase>& tabs, const Collections::IObservableVector<TabBase>& mruTabs)
void CommandPalette::SetTabs(const Collections::IObservableVector<Tab>& tabs, const Collections::IObservableVector<Tab>& mruTabs)
{
_bindTabs(tabs, _tabActions);
_bindTabs(mruTabs, _mruTabActions);
@ -1174,12 +1187,15 @@ namespace winrt::TerminalApp::implementation
}
else if (_currentMode == CommandPaletteMode::TabSearchMode || _currentMode == CommandPaletteMode::ActionMode || _currentMode == CommandPaletteMode::CommandlineMode)
{
auto pattern = std::make_shared<fzf::matcher::Pattern>(fzf::matcher::ParsePattern(searchText));
for (const auto& action : commandsToFilter)
{
// Update filter for all commands
// This will modify the highlighting but will also lead to re-computation of weight (and consequently sorting).
// Pay attention that it already updates the highlighting in the UI
action.UpdateFilter(searchText);
auto impl = winrt::get_self<implementation::FilteredCommand>(action);
impl->UpdateFilter(pattern);
// if there is active search we skip commands with 0 weight
if (searchText.empty() || action.Weight() > 0)

View File

@ -31,7 +31,7 @@ namespace winrt::TerminalApp::implementation
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> FilteredActions();
void SetTabs(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase>& tabs, const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase>& mruTabs);
void SetTabs(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::Tab>& tabs, const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::Tab>& mruTabs);
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
@ -48,7 +48,7 @@ namespace winrt::TerminalApp::implementation
void EnableTabSearchMode();
til::property_changed_event PropertyChanged;
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::TerminalApp::TabBase> SwitchToTabRequested;
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::TerminalApp::Tab> SwitchToTabRequested;
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::hstring> CommandLineExecutionRequested;
til::typed_event<winrt::TerminalApp::CommandPalette, Microsoft::Terminal::Settings::Model::Command> DispatchCommandRequested;
til::typed_event<Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command> PreviewAction;
@ -135,7 +135,7 @@ namespace winrt::TerminalApp::implementation
Microsoft::Terminal::Settings::Model::TabSwitcherMode _tabSwitcherMode;
uint32_t _switcherStartIdx;
void _bindTabs(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::TabBase>& source, const Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand>& target);
void _bindTabs(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::Tab>& source, const Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand>& target);
void _anchorKeyUpHandler();
winrt::Windows::UI::Xaml::Controls::ListView::SizeChanged_revoker _sizeChangedRevoker;

View File

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TabBase.idl";
import "Tab.idl";
import "HighlightedTextControl.idl";
import "FilteredCommand.idl";
@ -20,7 +20,7 @@ namespace TerminalApp
Windows.Foundation.Collections.IObservableVector<FilteredCommand> FilteredActions { get; };
void SetTabs(Windows.Foundation.Collections.IObservableVector<TabBase> tabs, Windows.Foundation.Collections.IObservableVector<TabBase> mruTabs);
void SetTabs(Windows.Foundation.Collections.IObservableVector<Tab> tabs, Windows.Foundation.Collections.IObservableVector<Tab> mruTabs);
void SetActionMap(Microsoft.Terminal.Settings.Model.IActionMapView actionMap);
@ -30,7 +30,7 @@ namespace TerminalApp
void EnableTabSwitcherMode(UInt32 startIdx, Microsoft.Terminal.Settings.Model.TabSwitcherMode tabSwitcherMode);
void EnableTabSearchMode();
event Windows.Foundation.TypedEventHandler<CommandPalette, TabBase> SwitchToTabRequested;
event Windows.Foundation.TypedEventHandler<CommandPalette, Tab> SwitchToTabRequested;
event Windows.Foundation.TypedEventHandler<CommandPalette, Microsoft.Terminal.Settings.Model.Command> DispatchCommandRequested;
event Windows.Foundation.TypedEventHandler<CommandPalette, String> CommandLineExecutionRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Command> PreviewAction;

View File

@ -44,6 +44,12 @@
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}" />
</Style>
<Style x:Key="SubtitleTextStyle"
TargetType="TextBlock">
<Setter Property="FontSize" Value="10" />
<Setter Property="Foreground" Value="{ThemeResource SystemBaseMediumColor}" />
</Style>
<DataTemplate x:Key="ListItemTemplate"
x:DataType="local:FilteredCommand">
<ListViewItem HorizontalContentAlignment="Stretch"
@ -71,10 +77,19 @@
Height="16"
Content="{x:Bind Item.ResolvedIcon, Mode=OneWay}" />
<local:HighlightedTextControl Grid.Column="1"
<StackPanel Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
Orientation="Vertical">
<local:HighlightedTextControl HorizontalAlignment="Left"
HighlightedRuns="{x:Bind NameHighlights, Mode=OneWay}"
Text="{x:Bind Item.Name, Mode=OneWay}" />
<local:HighlightedTextControl HorizontalAlignment="Left"
HighlightedRuns="{x:Bind SubtitleHighlights, Mode=OneWay}"
Text="{x:Bind Item.Subtitle, Mode=OneWay}"
TextBlockStyle="{StaticResource SubtitleTextStyle}"
Visibility="{x:Bind HasSubtitle, Mode=OneWay}" />
</StackPanel>
<!--
The block for the key chord is only visible
when there's actual text set as the label.
@ -121,9 +136,19 @@
Height="16"
Content="{x:Bind Item.ResolvedIcon, Mode=OneWay}" />
<local:HighlightedTextControl Grid.Column="1"
<StackPanel Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
Orientation="Vertical">
<local:HighlightedTextControl HorizontalAlignment="Left"
HighlightedRuns="{x:Bind NameHighlights, Mode=OneWay}"
Text="{x:Bind Item.Name, Mode=OneWay}" />
<local:HighlightedTextControl HorizontalAlignment="Left"
HighlightedRuns="{x:Bind SubtitleHighlights, Mode=OneWay}"
Text="{x:Bind Item.Subtitle, Mode=OneWay}"
TextBlockStyle="{StaticResource SubtitleTextStyle}"
Visibility="{x:Bind HasSubtitle, Mode=OneWay}" />
</StackPanel>
<!--
The block for the key chord is only visible
@ -192,7 +217,8 @@
<local:HighlightedTextControl Grid.Column="1"
HorizontalAlignment="Left"
Text="{x:Bind HighlightedName, Mode=OneWay}" />
HighlightedRuns="{x:Bind NameHighlights, Mode=OneWay}"
Text="{x:Bind Item.Name, Mode=OneWay}" />
<StackPanel Grid.Column="2"
HorizontalAlignment="Right"

View File

@ -2,11 +2,11 @@
// Licensed under the MIT license.
#include "pch.h"
#include "TabPaletteItem.h"
#include "TerminalTab.h"
#include "Tab.h"
#include <LibraryResources.h>
#include "TabPaletteItem.g.cpp"
#include "CommandPaletteItems.h"
using namespace winrt;
using namespace winrt::TerminalApp;
@ -19,42 +19,31 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
TabPaletteItem::TabPaletteItem(const winrt::TerminalApp::TabBase& tab) :
_tab(tab)
TabPaletteItem::TabPaletteItem(const winrt::TerminalApp::Tab& tab) :
_tab{ tab }
{
Name(tab.Title());
Icon(tab.Icon());
_tabChangedRevoker = tab.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& sender, auto& e) {
auto item{ weakThis.get() };
auto senderTab{ sender.try_as<winrt::TerminalApp::TabBase>() };
if (item && senderTab)
_tabChangedRevoker = tab.PropertyChanged(winrt::auto_revoke, [=](auto& sender, auto& e) {
if (auto senderTab{ sender.try_as<winrt::TerminalApp::Tab>() })
{
auto changedProperty = e.PropertyName();
if (changedProperty == L"Title")
{
item->Name(senderTab.Title());
BaseRaisePropertyChanged(L"Name");
}
else if (changedProperty == L"Icon")
{
item->Icon(senderTab.Icon());
BaseRaisePropertyChanged(L"Icon");
InvalidateResolvedIcon();
}
}
});
if (const auto terminalTab{ tab.try_as<winrt::TerminalApp::TerminalTab>() })
if (const auto status = tab.TabStatus())
{
const auto status = terminalTab.TabStatus();
TabStatus(status);
_tabStatusChangedRevoker = status.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& /*e*/) {
_tabStatusChangedRevoker = status.PropertyChanged(winrt::auto_revoke, [=](auto& /*sender*/, auto& /*e*/) {
// Sometimes nested bindings do not get updated,
// thus let's notify property changed on TabStatus when one of its properties changes
if (auto item{ weakThis.get() })
{
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
}
BaseRaisePropertyChanged(L"TabStatus");
});
}
}

View File

@ -0,0 +1,159 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "BasePaletteItem.h"
#include "TabPaletteItem.g.h"
#include "../inc/cppwinrt_utils.h"
namespace winrt::TerminalApp::implementation
{
struct ActionPaletteItem :
public winrt::implements<ActionPaletteItem, IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>,
BasePaletteItem<ActionPaletteItem, winrt::TerminalApp::PaletteItemType::Action>
{
ActionPaletteItem(const Microsoft::Terminal::Settings::Model::Command& command, const winrt::hstring keyChordText) :
_Command{ command }, _name{ command.Name() }, _keyChordText{ keyChordText }
{
static bool shouldShowSubtitles = [] {
try
{
const auto context{ winrt::Windows::ApplicationModel::Resources::Core::ResourceContext::GetForViewIndependentUse() };
const auto qualifiers{ context.QualifierValues() };
if (const auto language{ qualifiers.TryLookup(L"language") })
{
return !til::starts_with_insensitive_ascii(*language, L"en-");
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
return false;
}();
if (shouldShowSubtitles)
{
const auto subtitle = _Command.LanguageNeutralName();
if (subtitle != _name)
{
_subtitle = std::move(subtitle);
}
}
}
winrt::hstring Name()
{
return _name;
}
winrt::hstring Subtitle()
{
return _subtitle;
}
winrt::hstring KeyChordText()
{
return _keyChordText;
}
winrt::hstring Icon()
{
return _Command.Icon().Resolved();
}
WINRT_PROPERTY(Microsoft::Terminal::Settings::Model::Command, Command, nullptr);
private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _commandChangedRevoker;
winrt::hstring _name;
winrt::hstring _subtitle;
winrt::hstring _keyChordText;
};
struct CommandLinePaletteItem :
public winrt::implements<CommandLinePaletteItem, IPaletteItem, winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>,
BasePaletteItem<CommandLinePaletteItem, winrt::TerminalApp::PaletteItemType::CommandLine>
{
CommandLinePaletteItem(const winrt::hstring& commandLine) :
_CommandLine{ commandLine } {}
winrt::hstring Name()
{
return _CommandLine;
}
winrt::hstring Subtitle()
{
return {};
}
winrt::hstring KeyChordText()
{
return {};
}
winrt::hstring Icon()
{
return {};
}
WINRT_PROPERTY(winrt::hstring, CommandLine);
};
struct TabPaletteItem :
public TabPaletteItemT<TabPaletteItem>,
BasePaletteItem<TabPaletteItem, winrt::TerminalApp::PaletteItemType::Tab>
{
TabPaletteItem(const winrt::TerminalApp::Tab& tab);
winrt::TerminalApp::Tab Tab() const noexcept
{
return _tab.get();
}
winrt::hstring Name()
{
if (auto tab = _tab.get())
{
return tab.Title();
}
return {};
}
winrt::hstring Subtitle()
{
return {};
}
winrt::hstring KeyChordText()
{
return {};
}
winrt::hstring Icon()
{
if (auto tab = _tab.get())
{
return tab.Icon();
}
return {};
}
winrt::TerminalApp::TerminalTabStatus TabStatus()
{
if (auto tab = _tab.get())
{
return tab.TabStatus();
}
return { nullptr };
}
private:
winrt::weak_ref<winrt::TerminalApp::Tab> _tab;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabChangedRevoker;
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabStatusChangedRevoker;
};
}

View File

@ -3,8 +3,8 @@
#include "pch.h"
#include "CommandPalette.h"
#include "HighlightedText.h"
#include <LibraryResources.h>
#include "fzf/fzf.h"
#include "FilteredCommand.g.cpp"
@ -19,213 +19,96 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
// This class is a wrapper of PaletteItem, that is used as an item of a filterable list in CommandPalette.
// This class is a wrapper of IPaletteItem, that is used as an item of a filterable list in CommandPalette.
// It manages a highlighted text that is computed by matching search filter characters to item name
FilteredCommand::FilteredCommand(const winrt::TerminalApp::PaletteItem& item)
FilteredCommand::FilteredCommand(const winrt::TerminalApp::IPaletteItem& item) :
_Item{ item }, _Weight{ 0 }
{
// Actually implement the ctor in _constructFilteredCommand
_constructFilteredCommand(item);
}
// We need to actually implement the ctor in a separate helper. This is
// because we have a FilteredTask class which derives from FilteredCommand.
// HOWEVER, for cppwinrt ~ r e a s o n s ~, it doesn't actually derive from
// FilteredCommand directly, so we can't just use the FilteredCommand ctor
// directly in the base class.
void FilteredCommand::_constructFilteredCommand(const winrt::TerminalApp::PaletteItem& item)
{
_Item = item;
_Filter = L"";
_Weight = 0;
_HighlightedName = _computeHighlightedName();
// Recompute the highlighted name if the item name changes
_itemChangedRevoker = _Item.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& /*sender*/, auto& e) {
auto filteredCommand{ weakThis.get() };
if (filteredCommand && e.PropertyName() == L"Name")
// Our Item will not change, so we don't need to update the revoker if it does.
_itemChangedRevoker = _Item.as<winrt::Windows::UI::Xaml::Data::INotifyPropertyChanged>().PropertyChanged(winrt::auto_revoke, [=](auto& /*sender*/, auto& e) {
const auto property{ e.PropertyName() };
if (property == L"Name")
{
filteredCommand->HighlightedName(filteredCommand->_computeHighlightedName());
filteredCommand->Weight(filteredCommand->_computeWeight());
_update();
}
else if (property == L"Subtitle")
{
_update();
PropertyChanged.raise(*this, winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"HasSubtitle" });
}
});
}
void FilteredCommand::UpdateFilter(const winrt::hstring& filter)
void FilteredCommand::UpdateFilter(std::shared_ptr<fzf::matcher::Pattern> pattern)
{
// If the filter was not changed we want to prevent the re-computation of matching
// that might result in triggering a notification event
if (filter != _Filter)
if (pattern != _pattern)
{
Filter(filter);
HighlightedName(_computeHighlightedName());
Weight(_computeWeight());
_pattern = pattern;
_update();
}
}
// Method Description:
// - Looks up the filter characters within the item name.
// Iterating through the filter and the item name it tries to associate the next filter character
// with the first appearance of this character in the item name suffix.
//
// E.g., for filter="c l t s" and name="close all tabs after this", the match will be "CLose TabS after this".
//
// The item name is then split into segments (groupings of matched and non matched characters).
//
// E.g., the segments were the example above will be "CL", "ose ", "T", "ab", "S", "after this".
//
// The segments matching the filter characters are marked as highlighted.
//
// E.g., ("CL", true) ("ose ", false), ("T", true), ("ab", false), ("S", true), ("after this", false)
//
// TODO: we probably need to merge this logic with _getWeight computation?
//
// Return Value:
// - The HighlightedText object initialized with the segments computed according to the algorithm above.
winrt::TerminalApp::HighlightedText FilteredCommand::_computeHighlightedName()
bool FilteredCommand::HasSubtitle()
{
const auto segments = winrt::single_threaded_observable_vector<winrt::TerminalApp::HighlightedTextSegment>();
auto commandName = _Item.Name();
auto isProcessingMatchedSegment = false;
uint32_t nextOffsetToReport = 0;
uint32_t currentOffset = 0;
for (const auto searchChar : _Filter)
{
const WCHAR searchCharAsString[] = { searchChar, L'\0' };
while (true)
{
if (currentOffset == commandName.size())
{
// There are still unmatched filter characters but we finished scanning the name.
// In this case we return the entire item name as unmatched
auto entireNameSegment{ winrt::make<HighlightedTextSegment>(commandName, false) };
segments.Clear();
segments.Append(entireNameSegment);
return winrt::make<HighlightedText>(segments);
return !_Item.Subtitle().empty();
}
// GH#9941: search should be locale-aware as well
// We use the same comparison method as upon sorting to guarantee consistent behavior
const WCHAR currentCharAsString[] = { commandName[currentOffset], L'\0' };
auto isCurrentCharMatched = lstrcmpi(searchCharAsString, currentCharAsString) == 0;
if (isProcessingMatchedSegment != isCurrentCharMatched)
static std::tuple<std::vector<winrt::TerminalApp::HighlightedRun>, int32_t> _matchedSegmentsAndWeight(const std::shared_ptr<fzf::matcher::Pattern>& pattern, const winrt::hstring& haystack)
{
// We reached the end of the region (matched character came after a series of unmatched or vice versa).
// Conclude the segment and add it to the list.
// Skip segment if it is empty (might happen when the first character of the name is matched)
auto sizeToReport = currentOffset - nextOffsetToReport;
if (sizeToReport > 0)
std::vector<winrt::TerminalApp::HighlightedRun> segments;
int32_t weight = 0;
if (pattern && !pattern->terms.empty())
{
winrt::hstring segment{ commandName.data() + nextOffsetToReport, sizeToReport };
auto highlightedSegment{ winrt::make<HighlightedTextSegment>(segment, isProcessingMatchedSegment) };
segments.Append(highlightedSegment);
nextOffsetToReport = currentOffset;
}
isProcessingMatchedSegment = isCurrentCharMatched;
}
currentOffset++;
if (isCurrentCharMatched)
if (auto match = fzf::matcher::Match(haystack, *pattern.get()); match)
{
// We have matched this filter character, let's move to matching the next filter char
break;
auto& matchResult = *match;
weight = matchResult.Score;
segments.resize(matchResult.Runs.size());
std::transform(matchResult.Runs.begin(), matchResult.Runs.end(), segments.begin(), [](auto&& run) -> winrt::TerminalApp::HighlightedRun {
return { run.Start, run.End };
});
}
}
return { std::move(segments), weight };
}
// Either the filter or the item name were fully processed.
// If we were in the middle of the matched segment - add it.
if (isProcessingMatchedSegment)
void FilteredCommand::_update()
{
auto sizeToReport = currentOffset - nextOffsetToReport;
if (sizeToReport > 0)
auto itemName = _Item.Name();
auto [segments, weight] = _matchedSegmentsAndWeight(_pattern, itemName);
decltype(segments) subtitleSegments;
if (HasSubtitle())
{
winrt::hstring segment{ commandName.data() + nextOffsetToReport, sizeToReport };
auto highlightedSegment{ winrt::make<HighlightedTextSegment>(segment, true) };
segments.Append(highlightedSegment);
nextOffsetToReport = currentOffset;
}
auto itemSubtitle = _Item.Subtitle();
int32_t subtitleWeight = 0;
std::tie(subtitleSegments, subtitleWeight) = _matchedSegmentsAndWeight(_pattern, itemSubtitle);
weight = std::max(weight, subtitleWeight);
}
// Now create a segment for all remaining characters.
// We will have remaining characters as long as the filter is shorter than the item name.
auto sizeToReport = commandName.size() - nextOffsetToReport;
if (sizeToReport > 0)
if (segments.empty())
{
winrt::hstring segment{ commandName.data() + nextOffsetToReport, sizeToReport };
auto highlightedSegment{ winrt::make<HighlightedTextSegment>(segment, false) };
segments.Append(highlightedSegment);
NameHighlights(nullptr);
}
return winrt::make<HighlightedText>(segments);
}
// Function Description:
// - Calculates a "weighting" by which should be used to order a item
// 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"
// * Consecutive matches will be weighted higher than matches with
// characters in between the search characters.
// - This will return 0 if the item should not be shown. If all the
// characters of search text appear in order in `name`, then this function
// will return a positive number. 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:
// - the relative weight of this match
int FilteredCommand::_computeWeight()
else
{
auto result = 0;
auto isNextSegmentWordBeginning = true;
for (const auto& segment : _HighlightedName.Segments())
{
const auto& segmentText = segment.TextSegment();
const auto segmentSize = segmentText.size();
if (segment.IsHighlighted())
{
// Give extra point for each consecutive match
result += (segmentSize <= 1) ? segmentSize : 1 + 2 * (segmentSize - 1);
// Give extra point if this segment is at the beginning of a word
if (isNextSegmentWordBeginning)
{
result++;
}
NameHighlights(winrt::single_threaded_vector(std::move(segments)));
}
isNextSegmentWordBeginning = segmentSize > 0 && segmentText[segmentSize - 1] == L' ';
if (subtitleSegments.empty())
{
SubtitleHighlights(nullptr);
}
else
{
SubtitleHighlights(winrt::single_threaded_vector(std::move(subtitleSegments)));
}
return result;
Weight(weight);
}
// Function Description:
@ -243,9 +126,9 @@ namespace winrt::TerminalApp::implementation
if (firstWeight == secondWeight)
{
std::wstring_view firstName{ first.Item().Name() };
std::wstring_view secondName{ second.Item().Name() };
return lstrcmpi(firstName.data(), secondName.data()) < 0;
const auto firstName = first.Item().Name();
const auto secondName = second.Item().Name();
return til::compare_linguistic_insensitive(firstName, secondName) < 0;
}
return firstWeight > secondWeight;

View File

@ -5,6 +5,7 @@
#include "HighlightedTextControl.h"
#include "FilteredCommand.g.h"
#include "fzf/fzf.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
@ -17,24 +18,23 @@ namespace winrt::TerminalApp::implementation
struct FilteredCommand : FilteredCommandT<FilteredCommand>
{
FilteredCommand() = default;
FilteredCommand(const winrt::TerminalApp::PaletteItem& item);
FilteredCommand(const winrt::TerminalApp::IPaletteItem& item);
virtual void UpdateFilter(const winrt::hstring& filter);
void UpdateFilter(std::shared_ptr<fzf::matcher::Pattern> pattern);
static int Compare(const winrt::TerminalApp::FilteredCommand& first, const winrt::TerminalApp::FilteredCommand& second);
bool HasSubtitle();
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::PaletteItem, Item, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Filter, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedName, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::IPaletteItem, Item, PropertyChanged.raise, nullptr);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>, NameHighlights, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>, SubtitleHighlights, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(int, Weight, PropertyChanged.raise);
protected:
void _constructFilteredCommand(const winrt::TerminalApp::PaletteItem& item);
private:
winrt::TerminalApp::HighlightedText _computeHighlightedName();
int _computeWeight();
std::shared_ptr<fzf::matcher::Pattern> _pattern;
void _update();
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _itemChangedRevoker;
friend class TerminalAppLocalTests::FilteredCommandTests;

View File

@ -1,21 +1,20 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "PaletteItem.idl";
import "IPaletteItem.idl";
import "HighlightedTextControl.idl";
namespace TerminalApp
{
[default_interface] unsealed runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
FilteredCommand();
FilteredCommand(PaletteItem item);
FilteredCommand(IPaletteItem item);
PaletteItem Item { get; };
String Filter;
HighlightedText HighlightedName { get; };
IPaletteItem Item { get; };
IVector<HighlightedRun> NameHighlights { get; };
IVector<HighlightedRun> SubtitleHighlights { get; };
Boolean HasSubtitle { get; };
Int32 Weight;
void UpdateFilter(String filter);
}
}

View File

@ -1,31 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "HighlightedText.h"
#include "HighlightedTextSegment.g.cpp"
#include "HighlightedText.g.cpp"
using namespace winrt;
using namespace winrt::TerminalApp;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI::Text;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Microsoft::Terminal::Settings::Model;
namespace winrt::TerminalApp::implementation
{
HighlightedTextSegment::HighlightedTextSegment(const winrt::hstring& textSegment, bool isHighlighted) :
_TextSegment(textSegment),
_IsHighlighted(isHighlighted)
{
}
HighlightedText::HighlightedText(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>& segments) :
_Segments(segments)
{
}
}

View File

@ -1,35 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "HighlightedTextSegment.g.h"
#include "HighlightedText.g.h"
namespace winrt::TerminalApp::implementation
{
struct HighlightedTextSegment : HighlightedTextSegmentT<HighlightedTextSegment>
{
HighlightedTextSegment() = default;
HighlightedTextSegment(const winrt::hstring& text, bool isHighlighted);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, TextSegment, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsHighlighted, PropertyChanged.raise);
};
struct HighlightedText : HighlightedTextT<HighlightedText>
{
HighlightedText() = default;
HighlightedText(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>& segments);
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>, Segments, PropertyChanged.raise);
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(HighlightedTextSegment);
BASIC_FACTORY(HighlightedText);
}

View File

@ -1,22 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
[default_interface] runtimeclass HighlightedTextSegment : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
HighlightedTextSegment();
HighlightedTextSegment(String text, Boolean isMatched);
String TextSegment { get; };
Boolean IsHighlighted { get; };
}
[default_interface] runtimeclass HighlightedText : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
HighlightedText();
HighlightedText(Windows.Foundation.Collections.IObservableVector<HighlightedTextSegment> segments);
Windows.Foundation.Collections.IObservableVector<HighlightedTextSegment> Segments;
}
}

View File

@ -22,70 +22,152 @@ namespace winrt::TerminalApp::implementation
// Our control exposes a "Text" property to be used with Data Binding
// To allow this we need to register a Dependency Property Identifier to be used by the property system
// (https://docs.microsoft.com/en-us/windows/uwp/xaml-platform/custom-dependency-properties)
DependencyProperty HighlightedTextControl::_textProperty = DependencyProperty::Register(
L"Text",
xaml_typename<winrt::TerminalApp::HighlightedText>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata(nullptr, HighlightedTextControl::_onTextChanged));
DependencyProperty HighlightedTextControl::_TextProperty{ nullptr };
DependencyProperty HighlightedTextControl::_HighlightedRunsProperty{ nullptr };
DependencyProperty HighlightedTextControl::_TextBlockStyleProperty{ nullptr };
DependencyProperty HighlightedTextControl::_HighlightedRunStyleProperty{ nullptr };
HighlightedTextControl::HighlightedTextControl()
{
InitializeComponent();
_InitializeProperties();
}
// Method Description:
// - Returns the Identifier of the "Text" dependency property
DependencyProperty HighlightedTextControl::TextProperty()
void HighlightedTextControl::_InitializeProperties()
{
return _textProperty;
static auto [[maybe_unused]] registered = [] {
_TextProperty = DependencyProperty::Register(
L"Text",
xaml_typename<winrt::hstring>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata(nullptr, HighlightedTextControl::_onPropertyChanged));
_HighlightedRunsProperty = DependencyProperty::Register(
L"HighlightedRuns",
xaml_typename<winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata(nullptr, HighlightedTextControl::_onPropertyChanged));
_TextBlockStyleProperty = DependencyProperty::Register(
L"TextBlockStyle",
xaml_typename<winrt::Windows::UI::Xaml::Style>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata{ nullptr });
_HighlightedRunStyleProperty = DependencyProperty::Register(
L"HighlightedRunStyle",
xaml_typename<winrt::Windows::UI::Xaml::Style>(),
xaml_typename<winrt::TerminalApp::HighlightedTextControl>(),
PropertyMetadata(nullptr, HighlightedTextControl::_onPropertyChanged));
return true;
}();
}
// Method Description:
// - Returns the TextBlock view used to render the highlighted text
// Can be used when the Text property change is triggered by the event system to update the view
// We need to expose it rather than simply bind a data source because we update the runs in code-behind
Controls::TextBlock HighlightedTextControl::TextView()
{
return _textView();
}
winrt::TerminalApp::HighlightedText HighlightedTextControl::Text()
{
return winrt::unbox_value<winrt::TerminalApp::HighlightedText>(GetValue(_textProperty));
}
void HighlightedTextControl::Text(const winrt::TerminalApp::HighlightedText& value)
{
SetValue(_textProperty, winrt::box_value(value));
}
// Method Description:
// - This callback is triggered when the Text property is changed. Responsible for updating the view
// Arguments:
// - o - dependency object that was modified, expected to be an instance of this control
// - e - event arguments of the property changed event fired by the event system upon Text property change.
// The new value is expected to be an instance of HighlightedText
void HighlightedTextControl::_onTextChanged(const DependencyObject& o, const DependencyPropertyChangedEventArgs& e)
void HighlightedTextControl::_onPropertyChanged(const DependencyObject& o, const DependencyPropertyChangedEventArgs& /*e*/)
{
const auto control = o.try_as<winrt::TerminalApp::HighlightedTextControl>();
const auto highlightedText = e.NewValue().try_as<winrt::TerminalApp::HighlightedText>();
if (control && highlightedText)
if (control)
{
// Replace all the runs on the TextBlock
// Use IsHighlighted to decide if the run should be highlighted.
// To do - export the highlighting style into XAML
const auto inlinesCollection = control.TextView().Inlines();
winrt::get_self<HighlightedTextControl>(control)->_updateTextAndStyle();
}
}
void HighlightedTextControl::OnApplyTemplate()
{
_updateTextAndStyle();
}
static void _applyStyleToObject(const winrt::Windows::UI::Xaml::Style& style, const winrt::Windows::UI::Xaml::DependencyObject& object)
{
if (!style)
{
return;
}
static const auto fontWeightProperty{ winrt::Windows::UI::Xaml::Documents::TextElement::FontWeightProperty() };
const auto setters{ style.Setters() };
for (auto&& setterBase : setters)
{
const auto setter = setterBase.as<winrt::Windows::UI::Xaml::Setter>();
const auto property = setter.Property();
auto value = setter.Value();
if (property == fontWeightProperty) [[unlikely]]
{
// BODGY - The XAML compiler emits a boxed int32, but the dependency property
// here expects a boxed FontWeight (which also requires a u16. heh.)
// FontWeight is one of the few properties that is broken like this, and on Run it's the
// only one... so we can trivially check this case.
const auto weight{ winrt::unbox_value_or<int32_t>(value, static_cast<int32_t>(400)) };
value = winrt::box_value(winrt::Windows::UI::Text::FontWeight{ static_cast<uint16_t>(weight) });
}
object.SetValue(property, value);
}
}
void HighlightedTextControl::_updateTextAndStyle()
{
const auto textBlock = GetTemplateChild(L"TextView").try_as<winrt::Windows::UI::Xaml::Controls::TextBlock>();
if (!textBlock)
{
return;
}
const auto text = Text();
const auto runs = HighlightedRuns();
const auto inlinesCollection = textBlock.Inlines();
inlinesCollection.Clear();
for (const auto& match : highlightedText.Segments())
// The code below constructs local hstring instances because hstring is required to be null-terminated
// and slicing _does not_ guarantee null termination. Passing a sliced wstring_view directly into run.Text()
// (which is a winrt::param::hstring--different thing!--will result in an exception when the sliced portion
// is not null-terminated.
if (!text.empty())
{
const auto matchText = match.TextSegment();
const auto fontWeight = match.IsHighlighted() ? FontWeights::Bold() : FontWeights::Normal();
size_t lastPos = 0;
if (runs && runs.Size())
{
const auto runStyle = HighlightedRunStyle();
for (const auto& [start, end] : runs)
{
if (start > lastPos)
{
const hstring nonMatch{ til::safe_slice_abs(text, lastPos, static_cast<size_t>(start)) };
Documents::Run run;
run.Text(matchText);
run.FontWeight(fontWeight);
run.Text(nonMatch);
inlinesCollection.Append(run);
}
const hstring matchSeg{ til::safe_slice_abs(text, static_cast<size_t>(start), static_cast<size_t>(end + 1)) };
Documents::Run run;
run.Text(matchSeg);
if (runStyle) [[unlikely]]
{
_applyStyleToObject(runStyle, run);
}
else
{
// Default style: bold
run.FontWeight(FontWeights::Bold());
}
inlinesCollection.Append(run);
lastPos = static_cast<size_t>(end + 1);
}
}
// This will also be true if there are no runs at all
if (lastPos < text.size())
{
// checking lastPos here prevents a needless deep copy of the whole text in the no-match case
const hstring tail{ lastPos == 0 ? text : hstring{ til::safe_slice_abs(text, lastPos, SIZE_T_MAX) } };
Documents::Run run;
run.Text(tail);
inlinesCollection.Append(run);
}
}

View File

@ -3,8 +3,6 @@
#pragma once
#include "winrt/Microsoft.UI.Xaml.Controls.h"
#include "HighlightedTextControl.g.h"
namespace winrt::TerminalApp::implementation
@ -13,16 +11,17 @@ namespace winrt::TerminalApp::implementation
{
HighlightedTextControl();
static Windows::UI::Xaml::DependencyProperty TextProperty();
void OnApplyTemplate();
winrt::TerminalApp::HighlightedText Text();
void Text(const winrt::TerminalApp::HighlightedText& value);
Windows::UI::Xaml::Controls::TextBlock TextView();
DEPENDENCY_PROPERTY(winrt::hstring, Text);
DEPENDENCY_PROPERTY(winrt::Windows::Foundation::Collections::IVector<winrt::TerminalApp::HighlightedRun>, HighlightedRuns);
DEPENDENCY_PROPERTY(winrt::Windows::UI::Xaml::Style, TextBlockStyle);
DEPENDENCY_PROPERTY(winrt::Windows::UI::Xaml::Style, HighlightedRunStyle);
private:
static Windows::UI::Xaml::DependencyProperty _textProperty;
static void _onTextChanged(const Windows::UI::Xaml::DependencyObject& o, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
static void _InitializeProperties();
static void _onPropertyChanged(const Windows::UI::Xaml::DependencyObject& o, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
void _updateTextAndStyle();
};
}

View File

@ -1,15 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "HighlightedText.idl";
namespace TerminalApp
{
struct HighlightedRun
{
UInt64 Start;
UInt64 End;
};
[default_interface] runtimeclass HighlightedTextControl : Windows.UI.Xaml.Controls.Control
{
HighlightedTextControl();
String Text;
Windows.UI.Xaml.DependencyProperty TextProperty { get; };
HighlightedText Text;
Windows.UI.Xaml.Controls.TextBlock TextView { get; };
IVector<HighlightedRun> HighlightedRuns;
Windows.UI.Xaml.DependencyProperty HighlightedRunsProperty { get; };
Windows.UI.Xaml.Style TextBlockStyle;
Windows.UI.Xaml.DependencyProperty TextBlockStyleProperty { get; };
Windows.UI.Xaml.Style HighlightedRunStyle;
Windows.UI.Xaml.DependencyProperty HighlightedRunStyleProperty { get; };
}
}

View File

@ -1,11 +0,0 @@
<UserControl x:Class="TerminalApp.HighlightedTextControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="Transparent"
mc:Ignorable="d">
<TextBlock x:Name="_textView" />
</UserControl>

View File

@ -0,0 +1,23 @@
<!--
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT License. See LICENSE in the project root for license information.
-->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TerminalApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Style TargetType="local:HighlightedTextControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:HighlightedTextControl">
<TextBlock x:Name="TextView"
Style="{TemplateBinding TextBlockStyle}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TerminalTabStatus.idl";
namespace TerminalApp
{
enum PaletteItemType
{
Action,
CommandLine,
Tab,
};
interface IPaletteItem requires Windows.UI.Xaml.Data.INotifyPropertyChanged
{
PaletteItemType Type { get; };
String Name { get; };
String Subtitle { get; };
String KeyChordText { get; };
String Icon { get; };
Windows.UI.Xaml.Controls.IconElement ResolvedIcon { get; };
}
runtimeclass TabPaletteItem : [default] IPaletteItem, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
TerminalTabStatus TabStatus{ get; };
}
}

View File

@ -19,41 +19,6 @@ DEFINE_PROPERTYKEY(PKEY_AppUserModel_DestListLogoUri, 0x9F4C2855, 0x9F79, 0x4B39
{ 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 }, 29 \
}
// Function Description:
// - This function guesses whether a string is a file path.
static constexpr bool _isProbableFilePath(std::wstring_view path)
{
// "C:X", "C:\X", "\\?", "\\."
// _this function rejects \??\ as a path_
if (path.size() >= 3)
{
const auto firstColon{ path.find(L':') };
if (firstColon == 1)
{
return true;
}
const auto prefix{ path.substr(0, 2) };
return prefix == LR"(//)" || prefix == LR"(\\)";
}
return false;
}
// Function Description:
// - DestListLogoUri cannot take paths that are separated by / unless they're URLs.
// This function uses std::filesystem to normalize strings that appear to be file
// paths to have the "correct" slash direction.
static std::wstring _normalizeIconPath(std::wstring_view path)
{
const auto fullPath{ wil::ExpandEnvironmentStringsW<std::wstring>(path.data()) };
if (_isProbableFilePath(fullPath))
{
std::filesystem::path asPath{ fullPath };
return asPath.make_preferred().wstring();
}
return std::wstring{ fullPath };
}
// Method Description:
// - Updates the items of the Jumplist based on the given settings.
// Arguments:
@ -124,7 +89,7 @@ void Jumplist::_updateProfiles(IObjectCollection* jumplistItems, winrt::Windows:
auto args = fmt::format(FMT_COMPILE(L"-p {}"), to_hstring(profile.Guid()));
// Create the shell link object for the profile
const auto normalizedIconPath{ _normalizeIconPath(profile.Icon()) };
const auto normalizedIconPath{ profile.Icon().Resolved() };
const auto shLink = _createShellLink(profile.Name(), normalizedIconPath, args);
THROW_IF_FAILED(jumplistItems->AddObject(shLink.get()));
}

View File

@ -35,17 +35,23 @@ namespace winrt::TerminalApp::implementation
// (which should be the default, see:
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-trackmouseevent#remarks)
unsigned int hoverTimeoutMillis{ 400 };
LOG_IF_WIN32_BOOL_FALSE(SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hoverTimeoutMillis, 0));
const auto toolTipInterval = std::chrono::milliseconds(hoverTimeoutMillis);
if (FAILED(SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hoverTimeoutMillis, 0)))
{
hoverTimeoutMillis = 400;
}
// Create a ThrottledFunc for opening the tooltip after the hover
// timeout. If we hover another button, we should make sure to call
// Run() with the new button. Calling `_displayToolTip.Run(nullptr)`,
// which will cause us to not display a tooltip, which is used when we
// leave the control entirely.
_displayToolTip = std::make_shared<ThrottledFuncTrailing<Controls::Button>>(
_displayToolTip = std::make_shared<ThrottledFunc<Controls::Button>>(
dispatcher,
toolTipInterval,
til::throttled_func_options{
.delay = std::chrono::milliseconds{ hoverTimeoutMillis },
.debounce = true,
.trailing = true,
},
[weakThis = get_weak()](Controls::Button button) {
// If we provide a button, then open the tooltip on that button.
// We can "dismiss" this throttled func by calling it with null,

View File

@ -32,7 +32,7 @@ namespace winrt::TerminalApp::implementation
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MaximizeClick;
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> CloseClick;
std::shared_ptr<ThrottledFuncTrailing<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
std::shared_ptr<ThrottledFunc<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
std::optional<CaptionButton> _lastPressedButton{ std::nullopt };
};
}

View File

@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include <LibraryResources.h>
#include "PaletteItem.h"
#include "PaletteItem.g.cpp"
using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Windows::System;
namespace winrt::TerminalApp::implementation
{
Controls::IconElement PaletteItem::ResolvedIcon()
{
const auto icon = Microsoft::Terminal::UI::IconPathConverter::IconWUX(Icon());
icon.Width(16);
icon.Height(16);
return icon;
}
}

View File

@ -1,20 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaletteItem.g.h"
namespace winrt::TerminalApp::implementation
{
struct PaletteItem : PaletteItemT<PaletteItem>
{
public:
Windows::UI::Xaml::Controls::IconElement ResolvedIcon();
til::property_changed_event PropertyChanged;
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Name, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, KeyChordText, PropertyChanged.raise);
};
}

View File

@ -1,13 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
unsealed runtimeclass PaletteItem : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Name;
String KeyChordText;
String Icon;
Windows.UI.Xaml.Controls.IconElement ResolvedIcon { get; };
}
}

View File

@ -2,10 +2,11 @@
// Licensed under the MIT license.
#include "pch.h"
#include "TabPaletteItem.h"
#include "PaletteItemTemplateSelector.h"
#include "PaletteItemTemplateSelector.g.cpp"
#include "CommandPaletteItems.h"
namespace winrt::TerminalApp::implementation
{
Windows::UI::Xaml::DataTemplate PaletteItemTemplateSelector::SelectTemplateCore(const winrt::Windows::Foundation::IInspectable& item, const winrt::Windows::UI::Xaml::DependencyObject& /*container*/)
@ -26,16 +27,22 @@ namespace winrt::TerminalApp::implementation
{
if (const auto filteredCommand{ item.try_as<winrt::TerminalApp::FilteredCommand>() })
{
if (filteredCommand.Item().try_as<winrt::TerminalApp::TabPaletteItem>())
switch (filteredCommand.Item().Type())
{
case PaletteItemType::Tab:
return TabItemTemplate();
}
else if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
case PaletteItemType::Action:
{
if (actionPaletteItem.Command().HasNestedCommands())
const auto actionPaletteItem{ winrt::get_self<ActionPaletteItem>(filteredCommand.Item()) };
if (actionPaletteItem->Command().HasNestedCommands())
{
return NestedItemTemplate();
}
break; // Fall back to the general template
}
case PaletteItemType::CommandLine:
default:
break; // Fall back to the general template
}
}

View File

@ -697,12 +697,24 @@ bool Pane::SwapPanes(std::shared_ptr<Pane> first, std::shared_ptr<Pane> second)
// Refocus the last pane if there was a pane focused
if (const auto focus = first->GetActivePane())
{
focus->_Focus();
// GH#18184: manually focus the pane and content.
// _Focus() results in no-op because the pane was _lastActive
focus->GotFocus.raise(focus, FocusState::Programmatic);
if (const auto& lastContent{ focus->GetLastFocusedContent() })
{
lastContent.Focus(FocusState::Programmatic);
}
}
if (const auto focus = second->GetActivePane())
{
focus->_Focus();
// GH#18184: manually focus the pane and content.
// _Focus() results in no-op because the pane was _lastActive
focus->GotFocus.raise(focus, FocusState::Programmatic);
if (const auto& lastContent{ focus->GetLastFocusedContent() })
{
lastContent.Focus(FocusState::Programmatic);
}
}
return true;
@ -1040,7 +1052,7 @@ std::shared_ptr<Pane> Pane::GetActivePane()
// Arguments:
// - <none>
// Return Value:
// - nullptr if this Pane is an unfocused parent, otherwise the TermControl of this Pane.
// - nullptr if this Pane is an unfocused parent; otherwise, the TermControl of this Pane.
TermControl Pane::GetLastFocusedTerminalControl()
{
if (!_IsLeaf())
@ -1093,7 +1105,7 @@ IPaneContent Pane::GetLastFocusedContent()
// Arguments:
// - <none>
// Return Value:
// - nullptr if this Pane is a parent, otherwise the TermControl of this Pane.
// - nullptr if this Pane is a parent; otherwise, the TermControl of this Pane.
TermControl Pane::GetTerminalControl() const
{
if (const auto& terminalPane{ _getTerminalContent() })
@ -1402,6 +1414,13 @@ void Pane::_CloseChild(const bool closeFirst)
// take the control, profile, id and isDefTermSession of the pane that _wasn't_ closed.
_setPaneContent(remainingChild->_takePaneContent());
if (!_content)
{
// GH#18071: our content is still null after taking the other pane's content,
// so just notify our parent that we're closed.
Closed.raise(nullptr, nullptr);
return;
}
_id = remainingChild->Id();
// Revoke the old event handlers. Remove both the handlers for the panes
@ -1986,7 +2005,7 @@ void Pane::_SetupEntranceAnimation()
if (splitWidth)
{
// If we're animating the first child, then stick to the top/left of
// the parent pane, otherwise use the bottom/right. This is always
// the parent pane; otherwise, use the bottom/right. This is always
// the "outside" of the parent pane.
childGrid.HorizontalAlignment(isFirstChild ? HorizontalAlignment::Left : HorizontalAlignment::Right);
if (control)
@ -2011,7 +2030,7 @@ void Pane::_SetupEntranceAnimation()
else
{
// If we're animating the first child, then stick to the top/left of
// the parent pane, otherwise use the bottom/right. This is always
// the parent pane; otherwise, use the bottom/right. This is always
// the "outside" of the parent pane.
childGrid.VerticalAlignment(isFirstChild ? VerticalAlignment::Top : VerticalAlignment::Bottom);
if (control)
@ -2410,7 +2429,7 @@ std::optional<uint32_t> Pane::Id() noexcept
// Method Description:
// - Sets this pane's ID
// - Panes are given IDs upon creation by TerminalTab
// - Panes are given IDs upon creation by Tab
// Arguments:
// - The number to set this pane's ID to
void Pane::Id(uint32_t id) noexcept
@ -2526,7 +2545,7 @@ std::pair<float, float> Pane::_CalcChildrenSizes(const float fullSize) const
// user doesn't get any pane shrank when they actually expand the window or parent pane.
// That is also required by the layout algorithm.
// Arguments:
// - widthOrHeight: if true, operates on width, otherwise on height.
// - widthOrHeight: if true, operates on width; otherwise, on height.
// - fullSize: the amount of space in pixels that should be filled by our children and
// their separator. Can be arbitrarily low.
// Return Value:
@ -2588,7 +2607,7 @@ Pane::SnapChildrenSizeResult Pane::_CalcSnappedChildrenSizes(const bool widthOrH
// align with their character grids as close as possible. Snaps to closes match
// (either upward or downward). Also makes sure to fit in minimal sizes of the panes.
// Arguments:
// - widthOrHeight: if true operates on width, otherwise on height
// - widthOrHeight: if true operates on width; otherwise, on height
// - dimension: a dimension (width or height) to snap
// Return Value:
// - A value corresponding to the next closest snap size for this Pane, either upward or downward
@ -2603,7 +2622,7 @@ float Pane::CalcSnappedDimension(const bool widthOrHeight, const float dimension
// align with their character grids as close as possible. Also makes sure to
// fit in minimal sizes of the panes.
// Arguments:
// - widthOrHeight: if true operates on width, otherwise on height
// - widthOrHeight: if true operates on width; otherwise, on height
// - dimension: a dimension (width or height) to be snapped
// Return Value:
// - pair of floats, where first value is the size snapped downward (not greater than
@ -2690,11 +2709,11 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
// Method Description:
// - Increases size of given LayoutSizeNode to match next possible 'snap'. In case of leaf
// pane this means the next cell of the terminal. Otherwise it means that one of its children
// pane this means the next cell of the terminal. Otherwise, it means that one of its children
// advances (recursively). It expects the given node and its descendants to have either
// already snapped or minimum size.
// Arguments:
// - widthOrHeight: if true operates on width, otherwise on height.
// - widthOrHeight: if true operates on width; otherwise, on height.
// - sizeNode: a layout size node that corresponds to this pane.
// Return Value:
// - <none>
@ -2865,7 +2884,7 @@ Size Pane::_GetMinSize() const
// - Builds a tree of LayoutSizeNode that matches the tree of panes. Each node
// has minimum size that the corresponding pane can have.
// Arguments:
// - widthOrHeight: if true operates on width, otherwise on height
// - widthOrHeight: if true operates on width; otherwise, on height
// Return Value:
// - Root node of built tree that matches this pane.
Pane::LayoutSizeNode Pane::_CreateMinSizeTree(const bool widthOrHeight) const
@ -2885,7 +2904,7 @@ Pane::LayoutSizeNode Pane::_CreateMinSizeTree(const bool widthOrHeight) const
// - Adjusts split position so that no child pane is smaller then its
// minimum size
// Arguments:
// - widthOrHeight: if true, operates on width, otherwise on height.
// - widthOrHeight: if true, operates on width; otherwise, on height.
// - requestedValue: split position value to be clamped
// - totalSize: size (width or height) of the parent pane
// Return Value:

View File

@ -31,7 +31,7 @@ namespace TerminalAppLocalTests
namespace winrt::TerminalApp::implementation
{
struct TerminalTab;
struct Tab;
}
enum class Borders : int
@ -398,6 +398,6 @@ private:
LayoutSizeNode& operator=(const LayoutSizeNode& other);
};
friend struct winrt::TerminalApp::implementation::TerminalTab;
friend struct winrt::TerminalApp::implementation::Tab;
friend class ::TerminalAppLocalTests::TabTests;
};

View File

@ -15,19 +15,6 @@ using namespace winrt::Windows::Foundation;
namespace winrt::TerminalApp::implementation
{
CommandlineArgs::CommandlineArgs(winrt::array_view<const winrt::hstring> args, winrt::hstring currentDirectory, uint32_t showWindowCommand, winrt::hstring envString) :
_args{ args.begin(), args.end() },
CurrentDirectory{ std::move(currentDirectory) },
ShowWindowCommand{ showWindowCommand },
CurrentEnvironment{ std::move(envString) }
{
_parseResult = _parsed.ParseArgs(_args);
if (_parseResult == 0)
{
_parsed.ValidateStartupCommands();
}
}
::TerminalApp::AppCommandlineArgs& CommandlineArgs::ParsedArgs() noexcept
{
return _parsed;
@ -56,6 +43,11 @@ namespace winrt::TerminalApp::implementation
void CommandlineArgs::Commandline(const winrt::array_view<const winrt::hstring>& value)
{
_args = { value.begin(), value.end() };
_parseResult = _parsed.ParseArgs(_args);
if (_parseResult == 0)
{
_parsed.ValidateStartupCommands();
}
}
winrt::com_array<winrt::hstring> CommandlineArgs::Commandline()

View File

@ -13,21 +13,17 @@ namespace winrt::TerminalApp::implementation
{
struct CommandlineArgs : public CommandlineArgsT<CommandlineArgs>
{
CommandlineArgs() = default;
CommandlineArgs(winrt::array_view<const winrt::hstring> args, winrt::hstring currentDirectory, uint32_t showWindowCommand, winrt::hstring envString);
::TerminalApp::AppCommandlineArgs& ParsedArgs() noexcept;
winrt::com_array<winrt::hstring>& CommandlineRef() noexcept;
// These bits are exposed via WinRT:
public:
int32_t ExitCode() const noexcept;
winrt::hstring ExitMessage() const;
winrt::hstring TargetWindow() const;
til::property<winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection> Connection;
void Commandline(const winrt::array_view<const winrt::hstring>& value);
winrt::com_array<winrt::hstring> Commandline();
til::property<winrt::hstring> CurrentDirectory;
til::property<winrt::hstring> CurrentEnvironment;
til::property<uint32_t> ShowWindowCommand{ static_cast<uint32_t>(SW_NORMAL) }; // SW_NORMAL is 1, 0 is SW_HIDE
@ -86,11 +82,9 @@ namespace winrt::TerminalApp::implementation
WINRT_PROPERTY(uint64_t, Id);
WINRT_PROPERTY(winrt::hstring, WindowName);
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command);
WINRT_PROPERTY(TerminalApp::CommandlineArgs, Command, nullptr);
WINRT_PROPERTY(winrt::hstring, Content);
WINRT_PROPERTY(Windows::Foundation::IReference<Windows::Foundation::Rect>, InitialBounds);
private:
};
}

View File

@ -6,16 +6,16 @@ namespace TerminalApp
runtimeclass CommandlineArgs
{
CommandlineArgs();
CommandlineArgs(String[] args, String cwd, UInt32 showWindowCommand, String env);
Int32 ExitCode { get; };
String ExitMessage { get; };
String TargetWindow { get; };
Microsoft.Terminal.TerminalConnection.ITerminalConnection Connection;
String[] Commandline;
String CurrentDirectory { get; };
UInt32 ShowWindowCommand { get; };
String CurrentEnvironment { get; };
String CurrentDirectory;
UInt32 ShowWindowCommand;
String CurrentEnvironment;
};
enum MonitorBehavior

Some files were not shown because too many files have changed in this diff Show More