mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-19 03:10:49 +00:00
Merged PR 5568522: Migrate OSS up to a8b404463
Related work items: MSFT-31337042
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Dictionaries are lists of words to accept unconditionally
|
||||
|
||||
While check spelling will complain about a whitelisted word
|
||||
While check spelling will complain about an expected word
|
||||
which is no longer present, you can include things here even if
|
||||
they are not otherwise present in the repository.
|
||||
|
||||
|
||||
15
.github/actions/spell-check/dictionary/apis.txt
vendored
15
.github/actions/spell-check/dictionary/apis.txt
vendored
@@ -8,9 +8,12 @@ cmdletbinding
|
||||
COLORPROPERTY
|
||||
CXICON
|
||||
CYICON
|
||||
D2DERR_SHADER_COMPILE_FAILED
|
||||
DERR
|
||||
environstrings
|
||||
EXPCMDFLAGS
|
||||
EXPCMDSTATE
|
||||
frac
|
||||
fullkbd
|
||||
futex
|
||||
GETDESKWALLPAPER
|
||||
@@ -32,8 +35,8 @@ IInheritable
|
||||
IMap
|
||||
IObject
|
||||
IStorage
|
||||
ITab
|
||||
ITaskbar
|
||||
llabs
|
||||
LCID
|
||||
llabs
|
||||
localtime
|
||||
@@ -53,6 +56,7 @@ otms
|
||||
OUTLINETEXTMETRICW
|
||||
overridable
|
||||
PAGESCROLL
|
||||
pmr
|
||||
RETURNCMD
|
||||
rfind
|
||||
roundf
|
||||
@@ -63,18 +67,27 @@ semver
|
||||
serializer
|
||||
shobjidl
|
||||
SIZENS
|
||||
smoothstep
|
||||
GETDESKWALLPAPER
|
||||
snprintf
|
||||
spsc
|
||||
sregex
|
||||
STDCPP
|
||||
strchr
|
||||
Subheader
|
||||
Subpage
|
||||
UPDATEINIFILE
|
||||
syscall
|
||||
TBPF
|
||||
THEMECHANGED
|
||||
tmp
|
||||
tolower
|
||||
tx
|
||||
UPDATEINIFILE
|
||||
userenv
|
||||
wcsstr
|
||||
wcstoui
|
||||
wpc
|
||||
wsregex
|
||||
XDocument
|
||||
XElement
|
||||
|
||||
@@ -12,6 +12,7 @@ LKG
|
||||
mfcribbon
|
||||
microsoft
|
||||
microsoftonline
|
||||
muxc
|
||||
netcore
|
||||
osgvsowi
|
||||
pgc
|
||||
|
||||
@@ -12,16 +12,20 @@ ekg
|
||||
ethanschoonover
|
||||
Firefox
|
||||
Gatta
|
||||
glsl
|
||||
Grie
|
||||
Griese
|
||||
Hernan
|
||||
Howett
|
||||
Illhardt
|
||||
iquilezles
|
||||
jantari
|
||||
jerrysh
|
||||
Kaiyu
|
||||
kimwalisch
|
||||
KMehrain
|
||||
KODELIFE
|
||||
Kodelife
|
||||
Kourosh
|
||||
kowalczyk
|
||||
leonmsft
|
||||
@@ -30,6 +34,7 @@ lukesampson
|
||||
Manandhar
|
||||
mbadolato
|
||||
Mehrain
|
||||
menger
|
||||
mgravell
|
||||
michaelniksa
|
||||
michkap
|
||||
@@ -43,6 +48,7 @@ nvaccess
|
||||
nvda
|
||||
oising
|
||||
oldnewthing
|
||||
opengl
|
||||
osgwiki
|
||||
paulcam
|
||||
pauldotknopf
|
||||
@@ -51,6 +57,7 @@ Pham
|
||||
Rincewind
|
||||
rprichard
|
||||
Schoonover
|
||||
shadertoy
|
||||
Somuah
|
||||
sonph
|
||||
sonpham
|
||||
@@ -60,8 +67,8 @@ Wirt
|
||||
Wojciech
|
||||
zadjii
|
||||
Zamor
|
||||
Zamora
|
||||
zamora
|
||||
Zamora
|
||||
Zoey
|
||||
zorio
|
||||
Zverovich
|
||||
|
||||
31
.github/actions/spell-check/expect/expect.txt
vendored
31
.github/actions/spell-check/expect/expect.txt
vendored
@@ -24,8 +24,8 @@ ADDREF
|
||||
addressof
|
||||
ADDSTRING
|
||||
ADDTOOL
|
||||
AEnd
|
||||
aef
|
||||
AEnd
|
||||
AFew
|
||||
AFill
|
||||
AFX
|
||||
@@ -628,6 +628,7 @@ doskey
|
||||
dotnet
|
||||
doubleclick
|
||||
downlevel
|
||||
DOWNSCALE
|
||||
dpg
|
||||
dpi
|
||||
DPIAPI
|
||||
@@ -832,6 +833,7 @@ fuzzwrapper
|
||||
fwdecl
|
||||
fwe
|
||||
fwlink
|
||||
GAUSSIAN
|
||||
gb
|
||||
gci
|
||||
gcx
|
||||
@@ -909,6 +911,7 @@ Goldmine
|
||||
gonce
|
||||
Google
|
||||
goutput
|
||||
GPUs
|
||||
Gravell's
|
||||
grayscale
|
||||
GREENSCROLL
|
||||
@@ -1039,6 +1042,7 @@ IData
|
||||
IDCANCEL
|
||||
IDD
|
||||
IDesktop
|
||||
IDevice
|
||||
IDictionary
|
||||
IDISHWND
|
||||
IDisposable
|
||||
@@ -1109,6 +1113,7 @@ INTERCEPTCOPYPASTE
|
||||
INTERNALNAME
|
||||
interop
|
||||
interoperability
|
||||
intersectors
|
||||
inthread
|
||||
intptr
|
||||
intsafe
|
||||
@@ -1207,6 +1212,7 @@ KJ
|
||||
KLF
|
||||
KLMNOPQRST
|
||||
KLMNOPQRSTQQQQQ
|
||||
Kode
|
||||
KU
|
||||
KVM
|
||||
KX
|
||||
@@ -1497,6 +1503,7 @@ Nls
|
||||
NLSMODE
|
||||
NOACTIVATE
|
||||
NOAPPLYNOW
|
||||
NOCOMM
|
||||
NOCLIP
|
||||
NOCOLOR
|
||||
NOCONTEXTHELP
|
||||
@@ -1504,11 +1511,13 @@ NOCOPYBITS
|
||||
nodiscard
|
||||
NODUP
|
||||
noexcept
|
||||
NOHELP
|
||||
noinline
|
||||
NOINTEGRALHEIGHT
|
||||
NOINTERFACE
|
||||
NOLINKINFO
|
||||
nologo
|
||||
NOMCX
|
||||
NOMINMAX
|
||||
NOMOVE
|
||||
NONALERT
|
||||
@@ -1588,6 +1597,7 @@ OACR
|
||||
oauth
|
||||
objbase
|
||||
ocf
|
||||
ocolor
|
||||
odl
|
||||
oem
|
||||
oemcp
|
||||
@@ -1786,6 +1796,7 @@ pragma
|
||||
prc
|
||||
prealigned
|
||||
prebuilt
|
||||
precendence
|
||||
precomp
|
||||
prect
|
||||
prefast
|
||||
@@ -1831,6 +1842,7 @@ pshn
|
||||
PSHNOTIFY
|
||||
PSHORT
|
||||
pshpack
|
||||
psin
|
||||
PSINGLE
|
||||
psl
|
||||
psldl
|
||||
@@ -1879,10 +1891,12 @@ QWER
|
||||
qzmp
|
||||
RAII
|
||||
RALT
|
||||
rasterbar
|
||||
rasterfont
|
||||
rasterization
|
||||
rawinput
|
||||
RAWPATH
|
||||
raytracers
|
||||
razzlerc
|
||||
rbar
|
||||
rbegin
|
||||
@@ -1953,9 +1967,11 @@ RESETCONTENT
|
||||
resheader
|
||||
resizable
|
||||
resmimetype
|
||||
reso
|
||||
restrictedcapabilities
|
||||
resw
|
||||
resx
|
||||
RETROII
|
||||
retval
|
||||
rfa
|
||||
rfc
|
||||
@@ -2026,11 +2042,14 @@ SBCSDBCS
|
||||
sbi
|
||||
sbiex
|
||||
sbold
|
||||
sbri
|
||||
scanbri
|
||||
scancode
|
||||
scanline
|
||||
schemename
|
||||
SCL
|
||||
scm
|
||||
scol
|
||||
scprintf
|
||||
SCRBUF
|
||||
SCRBUFSIZE
|
||||
@@ -2164,6 +2183,9 @@ SOURCESDIRECTORY
|
||||
SPACEBAR
|
||||
spammy
|
||||
spand
|
||||
spe
|
||||
sph
|
||||
spherefunctions
|
||||
splashscreen
|
||||
sprintf
|
||||
sqlproj
|
||||
@@ -2293,6 +2315,7 @@ tellp
|
||||
telnet
|
||||
telnetd
|
||||
templated
|
||||
teraflop
|
||||
terminalcore
|
||||
TERMINALSCROLLING
|
||||
terminfo
|
||||
@@ -2541,6 +2564,7 @@ vga
|
||||
vgaoem
|
||||
viewkind
|
||||
viewports
|
||||
Viginetting
|
||||
Virt
|
||||
VIRTTERM
|
||||
Virtualizing
|
||||
@@ -2757,6 +2781,7 @@ wwaproj
|
||||
WWith
|
||||
wx
|
||||
wxh
|
||||
wz
|
||||
xa
|
||||
xact
|
||||
xamarin
|
||||
@@ -2806,7 +2831,10 @@ xutr
|
||||
xvalue
|
||||
XVIRTUALSCREEN
|
||||
XWalk
|
||||
XWV
|
||||
xy
|
||||
xyw
|
||||
Xzn
|
||||
yact
|
||||
YAML
|
||||
YCast
|
||||
@@ -2822,6 +2850,7 @@ YVIRTUALSCREEN
|
||||
Yw
|
||||
YWalk
|
||||
yx
|
||||
yzx
|
||||
Zc
|
||||
ZCmd
|
||||
ZCtrl
|
||||
|
||||
@@ -172,6 +172,7 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminal", "src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj", "{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}
|
||||
{CA5CAD1A-ABCD-429C-B551-8562EC954746} = {CA5CAD1A-ABCD-429C-B551-8562EC954746}
|
||||
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
|
||||
@@ -180,6 +181,7 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia\TerminalApp\dll\TerminalApp.vcxproj", "{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-9A12-429C-B551-8562EC954746} = {CA5CAD1A-9A12-429C-B551-8562EC954746}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
@@ -233,6 +235,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAppLib", "src\casca
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LocalTests_TerminalApp", "src\cascadia\LocalTests_TerminalApp\TerminalApp.LocalTests.vcxproj", "{CA5CAD1A-B11C-4DDB-A4FE-C3AFAE9B5506}"
|
||||
@@ -315,6 +318,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "s
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wt", "src\cascadia\wt\wt.vcxproj", "{506FD703-BAA7-4F6E-9361-64F550EC8FCA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Editor", "src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj", "{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {CA5CAD1A-082C-4476-9F33-94B339494076}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Settings.Model.Lib", "src\cascadia\TerminalSettingsModel\Microsoft.Terminal.Settings.ModelLib.vcxproj", "{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED} = {CA5CAD1A-44BD-4AC7-AC72-6CA5B3AB89ED}
|
||||
@@ -2012,6 +2020,45 @@ Global
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x64.Build.0 = Release|x64
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.Build.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|Any CPU.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|ARM64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|ARM64.Build.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|ARM64.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x64Test.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x64Test.Build.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x64Test.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x86Test.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x86Test.Build.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|DotNet_x86Test.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x64.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.AuditMode|x86.Deploy.0 = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Debug|x86.Deploy.0 = Debug|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x64.Build.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x64.Deploy.0 = Release|x64
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x86.Build.0 = Release|Win32
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32}.Release|x86.Deploy.0 = Release|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
@@ -2170,6 +2217,7 @@ Global
|
||||
{6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87}
|
||||
{1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-082C-4476-9F33-94B339494076} = {59840756-302F-44DF-AA47-441A9D673202}
|
||||
{CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<SignConfigXML>
|
||||
<job platform="" configuration="" dest="__INPATHROOT__" jobname="EngFunSimpleSign" approvers="">
|
||||
<file src="__INPATHROOT__\Microsoft.Terminal*.nupkg" signType="NuGet" />
|
||||
</job>
|
||||
</SignConfigXML>
|
||||
@@ -1,5 +0,0 @@
|
||||
<SignConfigXML>
|
||||
<job platform="" configuration="" certSubject="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" jobname="EngFunSimpleSign" approvers="">
|
||||
<file src="__INPATHROOT__\Microsoft.WindowsTerminal*.msixbundle" signType="136020001" />
|
||||
</job>
|
||||
</SignConfigXML>
|
||||
@@ -11,7 +11,7 @@
|
||||
- Yes, the large majority of the `DEFINE_PROPERTYKEY` defs are the same, it's only the last byte of the guid that changes
|
||||
|
||||
2. Add matching fields to Settings.hpp
|
||||
- add getters, setters, the whole drill.
|
||||
- Add getters, setters, the whole drill.
|
||||
|
||||
3. Add to the propsheet
|
||||
- We need to add it to *reading and writing* the registry from the propsheet, and *reading* the link from the propsheet. Yes, that's weird, but the propsheet is smart enough to re-use ShortcutSerialization::s_SetLinkValues, but not smart enough to do the same with RegistrySerialization.
|
||||
|
||||
14
doc/TAEF.md
14
doc/TAEF.md
@@ -48,3 +48,17 @@ Invoke-OpenConsoleTests
|
||||
```
|
||||
|
||||
`Invoke-OpenConsoleTests` supports a number of options, which you can enumerate by running `Invoke-OpenConsoleTests -?`.
|
||||
|
||||
|
||||
### Debugging Tests
|
||||
|
||||
If you want to debug a test, you can do so by using the TAEF /waitForDebugger flag, such as:
|
||||
|
||||
runut *Tests.dll /name:TextBufferTests::TestInsertCharacter /waitForDebugger
|
||||
|
||||
Replace the test name with the one you want to debug. Then, TAEF will begin executing the test and output something like this:
|
||||
|
||||
TAEF: Waiting for debugger - PID <some PID> @ IP <some IP address>
|
||||
|
||||
You can then attach to that PID in your debugger of choice. In Visual Studio, you can use Debug -> Attach To Process, or you could use WinDbg or whatever you want.
|
||||
Once the debugger attaches, the test will execute and your breakpoints will be hit.
|
||||
|
||||
395
doc/cascadia/AddASetting.md
Normal file
395
doc/cascadia/AddASetting.md
Normal file
@@ -0,0 +1,395 @@
|
||||
# Adding Settings to Windows Terminal
|
||||
|
||||
Adding a setting to Windows Terminal is fairly straightforward. This guide serves as a reference on how to add a setting.
|
||||
|
||||
## 1. Terminal Settings Model
|
||||
|
||||
The Terminal Settings Model (`Microsoft.Terminal.Settings.Model`) is responsible for (de)serializing and exposing settings.
|
||||
|
||||
### `GETSET_SETTING` macro
|
||||
|
||||
The `GETSET_SETTING` macro can be used to implement inheritance for your new setting and store the setting in the settings model. It takes three parameters:
|
||||
- `type`: the type that the setting will be stored as
|
||||
- `name`: the name of the variable for storage
|
||||
- `defaultValue`: the value to use if the user does not define the setting anywhere
|
||||
|
||||
### Adding a Profile setting
|
||||
|
||||
This tutorial will add `CloseOnExitMode CloseOnExit` as a profile setting.
|
||||
|
||||
1. In `Profile.h`, declare/define the setting:
|
||||
|
||||
```c++
|
||||
GETSET_SETTING(CloseOnExitMode, CloseOnExit, CloseOnExitMode::Graceful)
|
||||
```
|
||||
|
||||
2. In `Profile.idl`, expose the setting via WinRT:
|
||||
|
||||
```c++
|
||||
Boolean HasCloseOnExit();
|
||||
void ClearCloseOnExit();
|
||||
CloseOnExitMode CloseOnExit;
|
||||
```
|
||||
|
||||
3. In `Profile.cpp`, add (de)serialization and copy logic:
|
||||
|
||||
```c++
|
||||
// Top of file:
|
||||
// - Add the serialization key
|
||||
static constexpr std::string_view CloseOnExitKey{ "closeOnExit" };
|
||||
|
||||
// CopySettings() or Copy():
|
||||
// - The setting is exposed in the Settings UI
|
||||
profile->_CloseOnExit = source->_CloseOnExit;
|
||||
|
||||
// LayerJson():
|
||||
// - get the value from the JSON
|
||||
JsonUtils::GetValueForKey(json, CloseOnExitKey, _CloseOnExit);
|
||||
|
||||
// ToJson():
|
||||
// - write the value to the JSON
|
||||
JsonUtils::SetValueForKey(json, CloseOnExitKey, _CloseOnExit);
|
||||
```
|
||||
|
||||
- If the setting is not a primitive type, in `TerminalSettingsSerializationHelpers.h` add (de)serialization logic for the accepted values:
|
||||
|
||||
```c++
|
||||
// For enum values...
|
||||
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::CloseOnExitMode)
|
||||
{
|
||||
JSON_MAPPINGS(3) = {
|
||||
pair_type{ "always", ValueType::Always },
|
||||
pair_type{ "graceful", ValueType::Graceful },
|
||||
pair_type{ "never", ValueType::Never },
|
||||
};
|
||||
};
|
||||
|
||||
// For enum flag values...
|
||||
JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::TerminalControl::CopyFormat)
|
||||
{
|
||||
JSON_MAPPINGS(5) = {
|
||||
pair_type{ "none", AllClear },
|
||||
pair_type{ "html", ValueType::HTML },
|
||||
pair_type{ "rtf", ValueType::RTF },
|
||||
pair_type{ "all", AllSet },
|
||||
};
|
||||
};
|
||||
|
||||
// NOTE: This is also where you can add functionality for...
|
||||
// - overloaded type support (i.e. accept a bool and an enum)
|
||||
// - custom (de)serialization logic (i.e. coordinates)
|
||||
```
|
||||
|
||||
### Adding a Global setting
|
||||
|
||||
Follow the "adding a Profile setting" instructions above, but do it on the `GlobalAppSettings` files.
|
||||
|
||||
### Adding an Action
|
||||
|
||||
This tutorial will add the `openSettings` action.
|
||||
|
||||
1. In `KeyMapping.idl`, declare the action:
|
||||
|
||||
```c++
|
||||
// Add the action to ShortcutAction
|
||||
enum ShortcutAction
|
||||
{
|
||||
OpenSettings
|
||||
}
|
||||
```
|
||||
|
||||
2. In `ActionAndArgs.cpp`, add serialization logic:
|
||||
|
||||
```c++
|
||||
// Top of file:
|
||||
// - Add the serialization key
|
||||
static constexpr std::string_view OpenSettingsKey{ "openSettings" };
|
||||
|
||||
// ActionKeyNamesMap:
|
||||
// - map the new enum to the json key
|
||||
{ OpenSettingsKey, ShortcutAction::OpenSettings },
|
||||
```
|
||||
|
||||
3. If the action should automatically generate a name when it appears in the Command Palette...
|
||||
```c++
|
||||
// In ActionAndArgs.cpp GenerateName() --> GeneratedActionNames
|
||||
{ ShortcutAction::OpenSettings, RS_(L"OpenSettingsCommandKey") },
|
||||
|
||||
// In Resources.resw for Microsoft.Terminal.Settings.Model.Lib,
|
||||
// add the generated name
|
||||
// NOTE: Visual Studio presents the resw file as a table.
|
||||
// If you choose to edit the file with a text editor,
|
||||
// the code should look something like this...
|
||||
<data name="OpenSettingsCommandKey" xml:space="preserve">
|
||||
<value>Open settings file</value>
|
||||
</data>
|
||||
```
|
||||
|
||||
4. If the action supports arguments...
|
||||
- In `ActionArgs.idl`, declare the arguments
|
||||
```c++
|
||||
[default_interface] runtimeclass OpenSettingsArgs : IActionArgs
|
||||
{
|
||||
// this declares the "target" arg
|
||||
SettingsTarget Target { get; };
|
||||
};
|
||||
```
|
||||
- In `ActionArgs.h`, define the new runtime class
|
||||
```c++
|
||||
struct OpenSettingsArgs : public OpenSettingsArgsT<OpenSettingsArgs>
|
||||
{
|
||||
OpenSettingsArgs() = default;
|
||||
|
||||
// adds a getter/setter for your argument, and defines the json key
|
||||
GETSET_PROPERTY(SettingsTarget, Target, SettingsTarget::SettingsFile);
|
||||
static constexpr std::string_view TargetKey{ "target" };
|
||||
|
||||
public:
|
||||
hstring GenerateName() const;
|
||||
|
||||
bool Equals(const IActionArgs& other)
|
||||
{
|
||||
auto otherAsUs = other.try_as<OpenSettingsArgs>();
|
||||
if (otherAsUs)
|
||||
{
|
||||
return otherAsUs->_Target == _Target;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
static FromJsonResult FromJson(const Json::Value& json)
|
||||
{
|
||||
// LOAD BEARING: Not using make_self here _will_ break you in the future!
|
||||
auto args = winrt::make_self<OpenSettingsArgs>();
|
||||
JsonUtils::GetValueForKey(json, TargetKey, args->_Target);
|
||||
return { *args, {} };
|
||||
}
|
||||
|
||||
IActionArgs Copy() const
|
||||
{
|
||||
auto copy{ winrt::make_self<OpenSettingsArgs>() };
|
||||
copy->_Target = _Target;
|
||||
return *copy;
|
||||
}
|
||||
};
|
||||
```
|
||||
- In `ActionArgs.cpp`, define `GenerateName()`. This is used to automatically generate a name when it appears in the Command Palette.
|
||||
- In `ActionAndArgs.cpp`, add serialization logic:
|
||||
|
||||
```c++
|
||||
// ActionKeyNamesMap --> argParsers
|
||||
{ ShortcutAction::OpenSettings, OpenSettingsArgs::FromJson },
|
||||
```
|
||||
|
||||
### Adding an Action Argument
|
||||
|
||||
Follow step 3 from the "adding an Action" instructions above, but modify the relevant `ActionArgs` files.
|
||||
|
||||
## 2. Setting Functionality
|
||||
|
||||
Now that the Terminal Settings Model is updated, Windows Terminal can read and write to the settings file. This section covers how to add functionality to your newly created setting.
|
||||
|
||||
### App-level settings
|
||||
|
||||
App-level settings are settings that affect the frame of Windows Terminal. Generally, these tend to be global settings. The `TerminalApp` project is responsible for presenting the frame of Windows Terminal. A few files of interest include:
|
||||
- `TerminalPage`: XAML control responsible for the look and feel of Windows Terminal
|
||||
- `AppLogic`: WinRT class responsible for window-related issues (i.e. the titlebar, focus mode, etc...)
|
||||
|
||||
Both have access to a `CascadiaSettings` object, for you to read the loaded setting and update Windows Terminal appropriately.
|
||||
|
||||
### Terminal-level settings
|
||||
|
||||
Terminal-level settings are settings that affect a shell session. Generally, these tend to be profile settings. The `TerminalApp` project is responsible for packaging this settings from the Terminal Settings Model to the terminal instance. There are two kinds of settings here:
|
||||
- `IControlSettings`:
|
||||
- These are settings that affect the `TerminalControl` (a XAML control that hosts a shell session).
|
||||
- Examples include background image customization, interactivity behavior (i.e. selection), acrylic and font customization.
|
||||
- The `TerminalControl` project has access to these settings via a saved `IControlSettings` member.
|
||||
- `ICoreSettings`:
|
||||
- These are settings that affect the `TerminalCore` (a lower level object that interacts with the text buffer).
|
||||
- Examples include initial size, history size, and cursor customization.
|
||||
- The `TerminalCore` project has access to these settings via a saved `ICoreSettings` member.
|
||||
|
||||
`TerminalApp` packages these settings into a `TerminalSettings : IControlSettings, ICoreSettings` object upon creating a new terminal instance. To do so, you must submit the following changes:
|
||||
- Declare the setting in `IControlSettings.idl` or `ICoreSettings.idl` (whichever is relevant to your setting). If your setting is an enum setting, declare the enum here instead of in the `TerminalSettingsModel` project.
|
||||
- In `TerminalSettings.h`, declare/define the setting...
|
||||
```c++
|
||||
// The GETSET_PROPERTY macro declares/defines a getter setter for the setting.
|
||||
// Like GETSET_SETTING, it takes in a type, name, and defaultValue.
|
||||
GETSET_PROPERTY(bool, UseAcrylic, false);
|
||||
```
|
||||
- In `TerminalSettings.cpp`...
|
||||
- update `_ApplyProfileSettings` for profile settings
|
||||
- update `_ApplyGlobalSettings` for global settings
|
||||
- If additional processing is necessary, that would happen here. For example, `backgroundImageAlignment` is stored as a `ConvergedAlignment` in the Terminal Settings Model, but converted into XAML's separate horizontal and vertical alignment enums for packaging.
|
||||
|
||||
### Actions
|
||||
|
||||
Actions are packaged as an `ActionAndArgs` object, then handled in `TerminalApp`. To add functionality for actions...
|
||||
- In the `ShortcutActionDispatch` files, dispatch an event when the action occurs...
|
||||
```c++
|
||||
// ShortcutActionDispatch.idl
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> OpenSettings;
|
||||
|
||||
// ShortcutActionDispatch.h
|
||||
TYPED_EVENT(OpenSettings, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
|
||||
// ShortcutActionDispatch.cpp --> DoAction()
|
||||
// - dispatch the appropriate event
|
||||
case ShortcutAction::OpenSettings:
|
||||
{
|
||||
_OpenSettingsHandlers(*this, eventArgs);
|
||||
break;
|
||||
}
|
||||
```
|
||||
- In `TerminalPage` files, handle the event...
|
||||
```c++
|
||||
// TerminalPage.h
|
||||
// - declare the handler
|
||||
void _HandleOpenSettings(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
|
||||
// TerminalPage.cpp --> _RegisterActionCallbacks()
|
||||
// - register the handler
|
||||
_actionDispatch->OpenSettings({ this, &TerminalPage::_HandleOpenSettings });
|
||||
|
||||
// AppActionHandlers.cpp
|
||||
// - direct the function to the right place and call a helper function
|
||||
void TerminalPage::_HandleOpenSettings(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
// NOTE: this if-statement can be omitted if the action does not support arguments
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<OpenSettingsArgs>())
|
||||
{
|
||||
_LaunchSettings(realArgs.Target());
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`AppActionHandlers` vary based on the action you want to perform. A few useful helper functions include:
|
||||
- `_GetFocusedTab()`: retrieves the focused tab
|
||||
- `_GetActiveControl()`: retrieves the active terminal control
|
||||
- `_GetTerminalTabImpl()`: tries to cast the given tab as a `TerminalTab` (a tab that hosts a terminal instance)
|
||||
|
||||
|
||||
## 3. Settings UI
|
||||
|
||||
### Exposing Enum Settings
|
||||
If the new setting supports enums, you need to expose a map of the enum and the respective value in the Terminal Settings Model's `EnumMappings`:
|
||||
|
||||
```c++
|
||||
// EnumMappings.idl
|
||||
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Settings.Model.CloseOnExitMode> CloseOnExitMode { get; };
|
||||
|
||||
// EnumMappings.h
|
||||
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, CloseOnExitMode> CloseOnExitMode();
|
||||
|
||||
// EnumMappings.cpp
|
||||
// - this macro leverages the json enum mapper in TerminalSettingsSerializationHelper to expose
|
||||
// the mapped values across project boundaries
|
||||
DEFINE_ENUM_MAP(Model::CloseOnExitMode, CloseOnExitMode);
|
||||
```
|
||||
|
||||
### Binding and Localizing the Enum Setting
|
||||
|
||||
Find the page in the Settings UI that the new setting fits best in. In this example, we are adding `LaunchMode`.
|
||||
1. In `Launch.idl`, expose the bindable setting...
|
||||
```c++
|
||||
// Expose the current value for the setting
|
||||
IInspectable CurrentLaunchMode;
|
||||
|
||||
// Expose the list of possible values
|
||||
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> LaunchModeList { get; };
|
||||
```
|
||||
|
||||
2. In `Launch.h`, declare the bindable enum setting...
|
||||
```c++
|
||||
// the GETSET_BINDABLE_ENUM_SETTING macro accepts...
|
||||
// - name: the name of the setting
|
||||
// - enumType: the type of the setting
|
||||
// - settingsModelName: how to retrieve the setting (use State() to get access to the settings model)
|
||||
// - settingNameInModel: the name of the setting in the terminal settings model
|
||||
GETSET_BINDABLE_ENUM_SETTING(LaunchMode, Model::LaunchMode, State().Settings().GlobalSettings, LaunchMode);
|
||||
```
|
||||
|
||||
3. In `Launch.cpp`, populate these functions...
|
||||
```c++
|
||||
// Constructor (after InitializeComponent())
|
||||
// the INITIALIZE_BINDABLE_ENUM_SETTING macro accepts...
|
||||
// - name: the name of the setting
|
||||
// - enumMappingsName: the name from the TerminalSettingsModel's EnumMappings
|
||||
// - enumType: the type for the enum
|
||||
// - resourceSectionAndType: prefix for the localization
|
||||
// - resourceProperty: postfix for the localization
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING(LaunchMode, LaunchMode, LaunchMode, L"Globals_LaunchMode", L"Content");
|
||||
```
|
||||
|
||||
4. In `Resources.resw` for Microsoft.Terminal.Settings.Editor, add the localized text to expose each enum value. Use the following format: `<SettingGroup>_<SettingName><EnumValue>.Content`
|
||||
- `SettingGroup`:
|
||||
- `Globals` for global settings
|
||||
- `Profile` for profile settings
|
||||
- `SettingName`:
|
||||
- the Pascal-case format for the setting type (i.e. `LaunchMode` for `"launchMode"`)
|
||||
- `EnumValue`:
|
||||
- the json key for the setting value, but with the first letter capitalized (i.e. `Focus` for `"focus"`)
|
||||
- The resulting resw key should look something like this `Globals_LaunchModeFocus.Content`
|
||||
- This is the text that will be used in your control
|
||||
|
||||
### Updating the UI
|
||||
|
||||
#### Enum Settings
|
||||
|
||||
Now, create a XAML control in the relevant XAML file. Use the following tips and tricks to style everything appropriately:
|
||||
- Wrap the control in a `ContentPresenter` adhering to the `SettingContainerStyle` style
|
||||
- Bind `SelectedItem` to the relevant `Current<Setting>` (i.e. `CurrentLaunchMode`). Ensure it's a TwoWay binding
|
||||
- Bind `ItemsSource` to `<Setting>List` (i.e. `LaunchModeList`)
|
||||
- Set the ItemTemplate to the `Enum<ControlType>Template` (i.e. `EnumRadioButtonTemplate` for radio buttons)
|
||||
- Set the style to the appropriate one in `CommonResources.xaml`
|
||||
|
||||
```xml
|
||||
<!--Launch Mode-->
|
||||
<ContentPresenter Style="{StaticResource SettingContainerStyle}">
|
||||
<muxc:RadioButtons x:Uid="Globals_LaunchMode"
|
||||
SelectedItem="{x:Bind CurrentLaunchMode, Mode="TwoWay"}"
|
||||
ItemsSource="{x:Bind LaunchModeList}"
|
||||
ItemTemplate="{StaticResource EnumRadioButtonTemplate}"
|
||||
Style="{StaticResource RadioButtonsSettingStyle}"/>
|
||||
</ContentPresenter>
|
||||
```
|
||||
|
||||
To add any localized text, add a `x:Uid`, and access the relevant property via the Resources.resw file. For example, `Globals_LaunchMode.Header` sets the header for this control. You can also set the tooltip text like this:
|
||||
`Globals_DefaultProfile.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip`.
|
||||
|
||||
#### Non-Enum Settings
|
||||
|
||||
Continue to reference `CommonResources.xaml` for appropriate styling and wrap the control with a similar `ContentPresenter`. However, instead of binding to the `Current<Setting>` and `<Setting>List`, bind directly to the setting via the state. Binding a setting like `altGrAliasing` should look something like this:
|
||||
```xml
|
||||
<!--AltGr Aliasing-->
|
||||
<ContentPresenter Style="{StaticResource SettingContainerStyle}">
|
||||
<CheckBox x:Uid="Profile_AltGrAliasing"
|
||||
IsChecked="{x:Bind State.Profile.AltGrAliasing, Mode=TwoWay}"
|
||||
Style="{StaticResource CheckBoxSettingStyle}"/>
|
||||
</ContentPresenter>
|
||||
```
|
||||
|
||||
#### Profile Settings
|
||||
|
||||
If you are specifically adding a Profile setting, in addition to the steps above, you need to make the setting observable by modifying the `Profiles` files...
|
||||
```c++
|
||||
// Profiles.idl --> ProfileViewModel
|
||||
// - this declares the setting as observable using the type and the name of the setting
|
||||
OBSERVABLE_PROJECTED_SETTING(Microsoft.Terminal.Settings.Model.CloseOnExitMode, CloseOnExit);
|
||||
|
||||
// Profiles.h --> ProfileViewModel
|
||||
// - this defines the setting as observable off of the _profile object
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, CloseOnExit);
|
||||
|
||||
// Profiles.h --> ProfileViewModel
|
||||
// - if the setting cannot be inherited by another profile (aka missing the Clear() function), use the following macro instead:
|
||||
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, Guid);
|
||||
```
|
||||
|
||||
The `ProfilePageNavigationState` holds a `ProfileViewModel`, which wraps the `Profile` object from the Terminal Settings Model. The `ProfileViewModel` makes all of the profile settings observable.
|
||||
|
||||
### Actions
|
||||
|
||||
Actions are not yet supported in the Settings UI.
|
||||
@@ -103,13 +103,23 @@
|
||||
"toggleFocusMode",
|
||||
"toggleFullscreen",
|
||||
"togglePaneZoom",
|
||||
"toggleRetroEffect",
|
||||
"toggleShaderEffects",
|
||||
"wt",
|
||||
"unbound"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"Direction": {
|
||||
"FocusDirection": {
|
||||
"enum": [
|
||||
"left",
|
||||
"right",
|
||||
"up",
|
||||
"down",
|
||||
"previous"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ResizeDirection": {
|
||||
"enum": [
|
||||
"left",
|
||||
"right",
|
||||
@@ -298,9 +308,9 @@
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "moveFocus" },
|
||||
"direction": {
|
||||
"$ref": "#/definitions/Direction",
|
||||
"$ref": "#/definitions/FocusDirection",
|
||||
"default": "left",
|
||||
"description": "The direction to move focus in, between panes"
|
||||
"description": "The direction to move focus in, between panes. Direction can be 'previous' to move to the most recently used pane."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,9 +325,9 @@
|
||||
"properties": {
|
||||
"action": { "type": "string", "pattern": "resizePane" },
|
||||
"direction": {
|
||||
"$ref": "#/definitions/Direction",
|
||||
"$ref": "#/definitions/ResizeDirection",
|
||||
"default": "left",
|
||||
"description": "The direction to move the pane separator in"
|
||||
"description": "The direction to move the pane separator in."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,10 +342,7 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"pattern": "sendInput"
|
||||
},
|
||||
"action": { "type": "string", "pattern": "sendInput" },
|
||||
"input": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
@@ -362,6 +369,13 @@
|
||||
"splitMode": {
|
||||
"default": "duplicate",
|
||||
"description": "Control how the pane splits. Only accepts \"duplicate\" which will duplicate the focused pane's profile into a new pane."
|
||||
},
|
||||
"size": {
|
||||
"default": 0.5,
|
||||
"description": "Specify how large the new pane should be, as a fraction of the current pane's size. 1.0 would be 'all of the current pane', and 0.0 is 'None of the parent'. Accepts floating point values from 0-1 (default 0.5).",
|
||||
"maximum": 1,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,10 +389,7 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"pattern": "openSettings"
|
||||
},
|
||||
"action": { "type": "string", "pattern": "openSettings" },
|
||||
"target": {
|
||||
"type": "string",
|
||||
"default": "settingsFile",
|
||||
@@ -453,9 +464,9 @@
|
||||
"index": {
|
||||
"oneOf": [
|
||||
{ "type": "integer" },
|
||||
{ "type": null }
|
||||
{ "type": "null" }
|
||||
],
|
||||
"default": "",
|
||||
"default": null,
|
||||
"description": "Close the tabs other than the one at this index. If no index is provided, use the focused tab's index."
|
||||
}
|
||||
}
|
||||
@@ -472,9 +483,9 @@
|
||||
"index": {
|
||||
"oneOf": [
|
||||
{ "type": "integer" },
|
||||
{ "type": null }
|
||||
{ "type": "null" }
|
||||
],
|
||||
"default": "",
|
||||
"default": null,
|
||||
"description": "Close the tabs following the tab at this index. If no index is provided, use the focused tab's index."
|
||||
}
|
||||
}
|
||||
@@ -834,7 +845,8 @@
|
||||
"desktopWallpaper"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"type": [ "string", "null" ]
|
||||
},
|
||||
"backgroundImageAlignment": {
|
||||
"default": "center",
|
||||
@@ -931,6 +943,10 @@
|
||||
"description": "When set to true, enable retro terminal effects. This is an experimental feature, and its continued existence is not guaranteed.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.pixelShaderPath": {
|
||||
"description": "Use to set a path to a pixel shader to use with the Terminal. Overrides `experimental.retroTerminalEffect`. This is an experimental feature, and its continued existence is not guaranteed.",
|
||||
"type": "string"
|
||||
},
|
||||
"fontFace": {
|
||||
"default": "Cascadia Mono",
|
||||
"description": "Name of the font face used in the profile.",
|
||||
@@ -944,7 +960,7 @@
|
||||
},
|
||||
"fontWeight": {
|
||||
"default": "normal",
|
||||
"description": "Sets the weight (lightness or heaviness of the strokes) for the given font. Possible values:\n -\"thin\"\n -\"extra-light\"\n -\"light\"\n -\"semi-light\"\n -\"normal\" (default)\n -\"medium\"\n -\"semi-bold\"\n -\"bold\"\n -\"extra-bold\"\n -\"black\"\n -\"extra-black\" or the corresponding numeric representation of OpenType font weight.",
|
||||
"description": "Sets the weight (lightness or heaviness of the strokes) for the given font. Possible values:\n -\"thin\"\n -\"extra-light\"\n -\"light\"\n -\"semi-light\"\n -\"normal\" (default)\n -\"medium\"\n -\"semi-bold\"\n -\"bold\"\n -\"extra-bold\"\n -\"black\"\n -\"extra-black\"\n or the corresponding numeric representation of OpenType font weight.",
|
||||
"oneOf": [
|
||||
{
|
||||
"enum": [
|
||||
|
||||
BIN
doc/specs/#1564 - Settings UI/add-new-profile.png
Normal file
BIN
doc/specs/#1564 - Settings UI/add-new-profile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
146
doc/specs/#1564 - Settings UI/cascading-settings.md
Normal file
146
doc/specs/#1564 - Settings UI/cascading-settings.md
Normal file
@@ -0,0 +1,146 @@
|
||||
---
|
||||
authors: Carlos Zamora (@carlos-zamora) and Kayla Cinnamon (@cinnamon-msft)
|
||||
created on: 2020-11-10
|
||||
last updated: 2020-11-19
|
||||
issue id: 1564
|
||||
---
|
||||
|
||||
# Cascading Settings
|
||||
|
||||
## 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.
|
||||
|
||||
This spec explores how to represent this feature in the Settings UI.
|
||||
|
||||
## Inspiration
|
||||
|
||||
Cascading settings (and `profiles.defaults` by extension) provide some major benefits:
|
||||
1. opt-in behavior for settings values provided in-box (i.e. reset to default)
|
||||
2. easy way to apply a setting to all your profiles
|
||||
3. (possible future feature) simple way to base a profile off of another profile
|
||||
|
||||
The following terminal emulators approach this issue as follows.
|
||||
| Terminal Emulator(s) | Relevant Features/Approach |
|
||||
|--|--|
|
||||
| ConEmu, Cmder | "Clone" a separate profile |
|
||||
| Fluent Terminal | "Restore Defaults" button on each page |
|
||||
| iTerm2 | "Bulk Copy from Selected Profile..." and "Duplicate Profile" |
|
||||
|
||||
Other Settings UIs have approached this issue as follows:
|
||||
| Project | Relevant Approach |
|
||||
|--|--|
|
||||
| Visual Studio | Present a dropdown with your options. An extra "\<inherit\>" option is shown to inherit a value from another place. |
|
||||
|
||||
## Solution Design
|
||||
|
||||
The XAML implementation will consist of introducing a `ContentControl` for each setting. The `ContentControl` simply wraps the XAML control used for a setting, then adds the chosen UI approach below.
|
||||
|
||||
The `ContentControl` will take advantage of the following TerminalSettingsModel APIs for each setting:
|
||||
```c++
|
||||
// Note: String and "Name" are replaced for each setting
|
||||
bool HasName();
|
||||
void ClearName();
|
||||
String Name();
|
||||
void Name(String val);
|
||||
```
|
||||
|
||||
## UI/UX Design Proposals
|
||||
|
||||
The proposals below will be used in combination with each other.
|
||||
|
||||
### 1: Text under a setting control
|
||||
|
||||
This design renames the "Global" page under Profiles to "Base layer". Settings that override those in profile.defaults will get text under the control saying "Overrides Base layer.". Next to the titles of controls that override the base layer is a reset button with a tooltip that says "Reset".
|
||||
|
||||

|
||||
|
||||
### Add New --> Duplicate Profile
|
||||
|
||||
The Add new profile button in the navigation menu would take you to a new page. This page will have radio buttons listing your profiles along with a default settings option. The user can choose to either duplicate a profile or create a new one from the default settings. Once the user makes a selection, the settings UI will take them to their new profile page. The fields on that profile page will be filled according to which profile selection the user made.
|
||||
|
||||

|
||||
|
||||
### Reset Profile button
|
||||
|
||||
On the Advanced pivot of a profile's page, there will be a button at the bottom for resetting a profile called "Reset to default settings". This button will remove the user's custom settings inside this profile's object and reset it to defaults, prioritizing profile.defaults then defaults.json.
|
||||
|
||||
### "Apply to all profiles" button
|
||||
|
||||
A way we could apply settings to all profiles is by adding a "Copy settings to..." button to the Advanced page of each profile. This button will open a content dialog with a tree view listing every profile setting. The user can select which settings they would like to copy over to another profile. At the bottom of the content dialog will list the user's profiles with checkboxes, allowing them to pick which profiles they'd like to copy settings to.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Previously considered ideas
|
||||
|
||||
These ideas were considered however we will not be moving forward with them.
|
||||
|
||||
### 1: \<inherit\> option
|
||||
|
||||
Each setting is an Editable ComboBox (except for boolean and enumerable settings). For booleans, the items will be Enabled and Disabled in a regular ComboBox. Enumerable settings will have their options listed in a regular ComboBox. For integers, most commonly used numbers will be listed.
|
||||
|
||||

|
||||
|
||||
**Pros**
|
||||
|
||||
- Doesn't clutter the screen.
|
||||
|
||||
**Cons**
|
||||
|
||||
- Every setting is a dropdown.
|
||||
|
||||
**Pitfalls**
|
||||
|
||||
- How will color pickers work with this scenario?
|
||||
|
||||
**Other considerations**
|
||||
|
||||
Each dropdown has either "inherit" or "custom". If the user selects "custom", the original control will appear (i.e. a color picker for colors or a number picker for integers).
|
||||
|
||||
This option was not chosen because it added too much overhead for changing a setting. For example, if you wanted to enable acrylic, you'd have to click the dropdown, select custom, watch the checkbox appear, and then select the checkbox.
|
||||
|
||||
### 2: Lock Button
|
||||
|
||||
Every setting will have a lock button next to it. If the lock is locked, that means the setting is being inherited from Global, and the control is disabled. If the user wants to edit the setting, they can click the lock, which will changed it to the unlocked lock icon, and the control will become enabled.
|
||||
|
||||

|
||||
|
||||
**Pros**
|
||||
|
||||
- Least amount of clutter on the screen while still keeping the original controls
|
||||
|
||||
**Cons**
|
||||
|
||||
- The lock concept is slightly confusing. Some may assume locking the setting means that it *won't* be inherited from Global and that it's "locked" to the profile. This is the opposite case for its current design. However, flipping the logic of the locks wouldn't make sense with an unlocked lock and a disabled control.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Accessibility
|
||||
|
||||
All of these additions to the settings UI will have to be accessibility tested.
|
||||
|
||||
### Security
|
||||
|
||||
These changes will not impact security.
|
||||
|
||||
### Reliability
|
||||
|
||||
These changes will not impact reliability.
|
||||
|
||||
### Compatibility
|
||||
|
||||
The partial parity with JSON route will give the settings UI a different compatibility from the JSON file itself. This is not necessarily a bad thing. The settings UI is intended to be a simplistic way for people to successfully edit their settings. If too many options are added to give it fully parity with JSON, it could compromise the simplistic benefit the settings UI provides.
|
||||
|
||||
### Performance, Power, and Efficiency
|
||||
|
||||
These changes will not impact performance, power, nor efficiency.
|
||||
|
||||
## Potential Issues
|
||||
|
||||
## Future considerations
|
||||
|
||||
When we add profile inheritance later, we can implement a layering page using a rearrangeable TreeView.
|
||||
|
||||
## Resources
|
||||
BIN
doc/specs/#1564 - Settings UI/copy-settings-1.png
Normal file
BIN
doc/specs/#1564 - Settings UI/copy-settings-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 364 KiB |
BIN
doc/specs/#1564 - Settings UI/copy-settings-2.png
Normal file
BIN
doc/specs/#1564 - Settings UI/copy-settings-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 362 KiB |
BIN
doc/specs/#1564 - Settings UI/inheritance-dropdown.png
Normal file
BIN
doc/specs/#1564 - Settings UI/inheritance-dropdown.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 266 KiB |
BIN
doc/specs/#1564 - Settings UI/inheritance-locks.png
Normal file
BIN
doc/specs/#1564 - Settings UI/inheritance-locks.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 267 KiB |
BIN
doc/specs/#1564 - Settings UI/inheritance-text.png
Normal file
BIN
doc/specs/#1564 - Settings UI/inheritance-text.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 268 KiB |
18
samples/PixelShaders/Broken.hlsl
Normal file
18
samples/PixelShaders/Broken.hlsl
Normal file
@@ -0,0 +1,18 @@
|
||||
// Broken, can be used for explorative testing of pixel shader error handling
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
cbuffer PixelShaderSettings {
|
||||
float Time;
|
||||
float Scale;
|
||||
float2 Resolution;
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
// OOPS; vec4 is not a hlsl but a glsl datatype!
|
||||
vec4 color = shaderTexture.Sample(samplerState, tex);
|
||||
|
||||
return color;
|
||||
}
|
||||
18
samples/PixelShaders/Error.hlsl
Normal file
18
samples/PixelShaders/Error.hlsl
Normal file
@@ -0,0 +1,18 @@
|
||||
// Shader used to indicate something went wrong during shader loading
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
cbuffer PixelShaderSettings {
|
||||
float Time;
|
||||
float Scale;
|
||||
float2 Resolution;
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
float4 color = shaderTexture.Sample(samplerState, tex);
|
||||
float bars = 0.5+0.5*sin(tex.y*100);
|
||||
color.x += pow(bars, 20.0);
|
||||
return color;
|
||||
}
|
||||
32
samples/PixelShaders/Grayscale.hlsl
Normal file
32
samples/PixelShaders/Grayscale.hlsl
Normal file
@@ -0,0 +1,32 @@
|
||||
// A minimal pixel shader that inverts the colors
|
||||
|
||||
// The terminal graphics as a texture
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
// Terminal settings such as the resolution of the texture
|
||||
cbuffer PixelShaderSettings {
|
||||
// Time since pixel shader was enabled
|
||||
float Time;
|
||||
// UI Scale
|
||||
float Scale;
|
||||
// Resolution of the shaderTexture
|
||||
float2 Resolution;
|
||||
// Background color as rgba
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
// A pixel shader is a program that given a texture coordinate (tex) produces a color
|
||||
// Just ignore the pos parameter
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
// Read the color value at the current texture coordinate (tex)
|
||||
// float4 is tuple of 4 floats, rgba
|
||||
float4 color = shaderTexture.Sample(samplerState, tex);
|
||||
float avg = (color.x + color.y + color.z) / 3.0;
|
||||
// Inverts the rgb values (xyz) but don't touch the alpha (w)
|
||||
color.xyz = avg;
|
||||
|
||||
// Return the final color
|
||||
return color;
|
||||
}
|
||||
32
samples/PixelShaders/Invert.hlsl
Normal file
32
samples/PixelShaders/Invert.hlsl
Normal file
@@ -0,0 +1,32 @@
|
||||
// A minimal pixel shader that inverts the colors
|
||||
|
||||
// The terminal graphics as a texture
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
// Terminal settings such as the resolution of the texture
|
||||
cbuffer PixelShaderSettings {
|
||||
// Time since pixel shader was enabled
|
||||
float Time;
|
||||
// UI Scale
|
||||
float Scale;
|
||||
// Resolution of the shaderTexture
|
||||
float2 Resolution;
|
||||
// Background color as rgba
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
// A pixel shader is a program that given a texture coordinate (tex) produces a color
|
||||
// Just ignore the pos parameter
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
// Read the color value at the current texture coordinate (tex)
|
||||
// float4 is tuple of 4 floats, rgba
|
||||
float4 color = shaderTexture.Sample(samplerState, tex);
|
||||
|
||||
// Inverts the rgb values (xyz) but don't touch the alpha (w)
|
||||
color.xyz = 1.0 - color.xyz;
|
||||
|
||||
// Return the final color
|
||||
return color;
|
||||
}
|
||||
17
samples/PixelShaders/Nop.hlsl
Normal file
17
samples/PixelShaders/Nop.hlsl
Normal file
@@ -0,0 +1,17 @@
|
||||
// Does nothing, serves as an example of a minimal pixel shader
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
cbuffer PixelShaderSettings {
|
||||
float Time;
|
||||
float Scale;
|
||||
float2 Resolution;
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
float4 color = shaderTexture.Sample(samplerState, tex);
|
||||
|
||||
return color;
|
||||
}
|
||||
136
samples/PixelShaders/README.md
Normal file
136
samples/PixelShaders/README.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Pixel Shaders in Windows Terminal
|
||||
|
||||
Due to the sheer amount of computing power in GPUs, one can do awesome things with pixel shaders such as real-time fractal zoom, ray tracers and image processing.
|
||||
|
||||
Windows Terminal allows user to provide a pixel shader which will be applied to the terminal. To try it out, add the following setting to one of your profiles:
|
||||
|
||||
```
|
||||
"experimental.pixelShaderPath": "<path to a .hlsl pixel shader>"
|
||||
```
|
||||
> **Note**: if you specify a shader with `experimental.pixelShaderPath`, the Terminal will use that instead of the `experimental.retroTerminalEffect`.
|
||||
|
||||
To get started using pixel shaders in the Terminal, start with the following sample shader. This is `Invert.hlsl` in this directory:
|
||||
|
||||
```hlsl
|
||||
// A minimal pixel shader that inverts the colors
|
||||
|
||||
// The terminal graphics as a texture
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
// Terminal settings such as the resolution of the texture
|
||||
cbuffer PixelShaderSettings {
|
||||
// Time since pixel shader was enabled
|
||||
float Time;
|
||||
// UI Scale
|
||||
float Scale;
|
||||
// Resolution of the shaderTexture
|
||||
float2 Resolution;
|
||||
// Background color as rgba
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
// A pixel shader is a program that given a texture coordinate (tex) produces a color
|
||||
// Just ignore the pos parameter
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
// Read the color value at the current texture coordinate (tex)
|
||||
// float4 is tuple of 4 floats, rgba
|
||||
float4 color = shaderTexture.Sample(samplerState, tex);
|
||||
|
||||
// Inverts the rgb values (xyz) but don't touch the alpha (w)
|
||||
color.xyz = 1.0 - color.xyz;
|
||||
|
||||
// Return the final color
|
||||
return color;
|
||||
}
|
||||
```
|
||||
|
||||
Save this file as `C:\temp\invert.hlsl`, then update a profile with the setting:
|
||||
|
||||
```
|
||||
"experimental.pixelShaderEffect": "C:\\temp\\invert.hlsl"
|
||||
```
|
||||
|
||||
Once the settings file is saved, open a terminal with the changed profile. It should now invert the colors of the screen!
|
||||
|
||||
If your shader fails to compile, the Terminal will display a warning dialog and ignore it temporarily. After fixing your shader, touch the `settings.json` file again, or open a new tab, and the Terminal will try loading the shader again.
|
||||
|
||||
## HLSL
|
||||
|
||||
The language we use to write pixel shaders is called `HLSL`. It a `C`-like language, with some restrictions.You can't allocate memory, use pointers or recursion.
|
||||
What you get access to is computing power in the teraflop range on decently recent GPUs. This means writing real-time raytracers or other cool effects are in the realm of possibility.
|
||||
|
||||
[shadertoy](https://shadertoy.com/) is a great site that show case what's possible with pixel shaders (albeit in `GLSL`). For example this [menger sponge](https://www.shadertoy.com/view/4scXzn). Converting from `GLSL` to `HLSL` isn't overly hard once you gotten the hang of it.
|
||||
|
||||
## Adding some retro raster bars
|
||||
|
||||
Let's try a more complicated example. Raster bars was cool in the 80's, so let's add that. Start by modifying shader like so: (This is `Rasterbars.hlsl`)
|
||||
|
||||
```hlsl
|
||||
// A minimal pixel shader that shows some raster bars
|
||||
|
||||
// The terminal graphics as a texture
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
// Terminal settings such as the resolution of the texture
|
||||
cbuffer PixelShaderSettings {
|
||||
// Time since pixel shader was enabled
|
||||
float Time;
|
||||
// UI Scale
|
||||
float Scale;
|
||||
// Resolution of the shaderTexture
|
||||
float2 Resolution;
|
||||
// Background color as rgba
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
// A pixel shader is a program that given a texture coordinate (tex) produces a color
|
||||
// Just ignore the pos parameter
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
// Read the color value at the current texture coordinate (tex)
|
||||
// float4 is tuple of 4 floats, rgba
|
||||
float4 color = shaderTexture.Sample(samplerState, tex);
|
||||
|
||||
// Read the color value at some offset, will be used as shadow
|
||||
float4 ocolor = shaderTexture.Sample(samplerState, tex+2.0*Scale*float2(-1.0, -1.0)/Resolution.y);
|
||||
|
||||
// Thickness of raster
|
||||
const float thickness = 0.1;
|
||||
|
||||
float ny = floor(tex.y/thickness);
|
||||
float my = tex.y%thickness;
|
||||
const float pi = 3.141592654;
|
||||
|
||||
|
||||
// ny is used to compute the rasterbar base color
|
||||
float cola = ny*2.0*pi;
|
||||
float3 col = 0.75+0.25*float3(sin(cola*0.111), sin(cola*0.222), sin(cola*0.333));
|
||||
|
||||
// my is used to compute the rasterbar brightness
|
||||
// smoothstep is a great little function: https://en.wikipedia.org/wiki/Smoothstep
|
||||
float brightness = 1.0-smoothstep(0.0, thickness*0.5, abs(my - 0.5*thickness));
|
||||
|
||||
float3 rasterColor = col*brightness;
|
||||
|
||||
// lerp(x, y, a) is another very useful function: https://en.wikipedia.org/wiki/Linear_interpolation
|
||||
float3 final = rasterColor;
|
||||
// Create the drop shadow of the terminal graphics
|
||||
// .w is the alpha channel, 0 is fully transparent and 1 is fully opaque
|
||||
final = lerp(final, float(0.0), ocolor.w);
|
||||
// Draw the terminal graphics
|
||||
final = lerp(final, color.xyz, color.w);
|
||||
|
||||
// Return the final color, set alpha to 1 (ie opaque)
|
||||
return float4(final, 1.0);
|
||||
}
|
||||
```
|
||||
|
||||
Once reloaded, it should show some retro raster bars in the background, with a drop shadow to make the text more readable.
|
||||
|
||||
## Retro Terminal Effect
|
||||
|
||||
As a more complicated example, the Terminal's built-in `experimental.retroTerminalEffect` is included as the `Retro.hlsl` file in this directory. Feel free to modify and experiment!
|
||||
|
||||
58
samples/PixelShaders/Rasterbars.hlsl
Normal file
58
samples/PixelShaders/Rasterbars.hlsl
Normal file
@@ -0,0 +1,58 @@
|
||||
// A minimal pixel shader that shows some raster bars
|
||||
|
||||
// The terminal graphics as a texture
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
// Terminal settings such as the resolution of the texture
|
||||
cbuffer PixelShaderSettings {
|
||||
// Time since pixel shader was enabled
|
||||
float Time;
|
||||
// UI Scale
|
||||
float Scale;
|
||||
// Resolution of the shaderTexture
|
||||
float2 Resolution;
|
||||
// Background color as rgba
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
// A pixel shader is a program that given a texture coordinate (tex) produces a color
|
||||
// Just ignore the pos parameter
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
// Read the color value at the current texture coordinate (tex)
|
||||
// float4 is tuple of 4 floats, rgba
|
||||
float4 color = shaderTexture.Sample(samplerState, tex);
|
||||
|
||||
// Read the color value at some offset, will be used as shadow
|
||||
float4 ocolor = shaderTexture.Sample(samplerState, tex+2.0*Scale*float2(-1.0, -1.0)/Resolution.y);
|
||||
|
||||
// Thickness of raster
|
||||
const float thickness = 0.1;
|
||||
|
||||
float ny = floor(tex.y/thickness);
|
||||
float my = tex.y%thickness;
|
||||
const float pi = 3.141592654;
|
||||
|
||||
|
||||
// ny is used to compute the rasterbar base color
|
||||
float cola = ny*2.0*pi;
|
||||
float3 col = 0.75+0.25*float3(sin(cola*0.111), sin(cola*0.222), sin(cola*0.333));
|
||||
|
||||
// my is used to compute the rasterbar brightness
|
||||
// smoothstep is a great little function: https://en.wikipedia.org/wiki/Smoothstep
|
||||
float brightness = 1.0-smoothstep(0.0, thickness*0.5, abs(my - 0.5*thickness));
|
||||
|
||||
float3 rasterColor = col*brightness;
|
||||
|
||||
// lerp(x, y, a) is another very useful function: https://en.wikipedia.org/wiki/Linear_interpolation
|
||||
float3 final = rasterColor;
|
||||
// Create the drop shadow of the terminal graphics
|
||||
// .w is the alpha channel, 0 is fully transparent and 1 is fully opaque
|
||||
final = lerp(final, float(0.0), ocolor.w);
|
||||
// Draw the terminal graphics
|
||||
final = lerp(final, color.xyz, color.w);
|
||||
|
||||
// Return the final color, set alpha to 1 (ie opaque)
|
||||
return float4(final, 1.0);
|
||||
}
|
||||
83
samples/PixelShaders/Retro.hlsl
Normal file
83
samples/PixelShaders/Retro.hlsl
Normal file
@@ -0,0 +1,83 @@
|
||||
// The original retro pixel shader
|
||||
Texture2D shaderTexture;
|
||||
SamplerState samplerState;
|
||||
|
||||
cbuffer PixelShaderSettings {
|
||||
float Time;
|
||||
float Scale;
|
||||
float2 Resolution;
|
||||
float4 Background;
|
||||
};
|
||||
|
||||
#define SCANLINE_FACTOR 0.5
|
||||
#define SCALED_SCANLINE_PERIOD Scale
|
||||
#define SCALED_GAUSSIAN_SIGMA (2.0*Scale)
|
||||
|
||||
static const float M_PI = 3.14159265f;
|
||||
|
||||
float Gaussian2D(float x, float y, float sigma)
|
||||
{
|
||||
return 1/(sigma*sqrt(2*M_PI)) * exp(-0.5*(x*x + y*y)/sigma/sigma);
|
||||
}
|
||||
|
||||
float4 Blur(Texture2D input, float2 tex_coord, float sigma)
|
||||
{
|
||||
uint width, height;
|
||||
shaderTexture.GetDimensions(width, height);
|
||||
|
||||
float texelWidth = 1.0f/width;
|
||||
float texelHeight = 1.0f/height;
|
||||
|
||||
float4 color = { 0, 0, 0, 0 };
|
||||
|
||||
int sampleCount = 13;
|
||||
|
||||
for (int x = 0; x < sampleCount; x++)
|
||||
{
|
||||
float2 samplePos = { 0, 0 };
|
||||
|
||||
samplePos.x = tex_coord.x + (x - sampleCount/2) * texelWidth;
|
||||
for (int y = 0; y < sampleCount; y++)
|
||||
{
|
||||
samplePos.y = tex_coord.y + (y - sampleCount/2) * texelHeight;
|
||||
if (samplePos.x <= 0 || samplePos.y <= 0 || samplePos.x >= width || samplePos.y >= height) continue;
|
||||
|
||||
color += input.Sample(samplerState, samplePos) * Gaussian2D((x - sampleCount/2), (y - sampleCount/2), sigma);
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
float SquareWave(float y)
|
||||
{
|
||||
return 1 - (floor(y / SCALED_SCANLINE_PERIOD) % 2) * SCANLINE_FACTOR;
|
||||
}
|
||||
|
||||
float4 Scanline(float4 color, float4 pos)
|
||||
{
|
||||
float wave = SquareWave(pos.y);
|
||||
|
||||
// TODO:GH#3929 make this configurable.
|
||||
// Remove the && false to draw scanlines everywhere.
|
||||
if (length(color.rgb) < 0.2 && false)
|
||||
{
|
||||
return color + wave*0.1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return color * wave;
|
||||
}
|
||||
}
|
||||
|
||||
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
|
||||
{
|
||||
Texture2D input = shaderTexture;
|
||||
|
||||
// TODO:GH#3930 Make these configurable in some way.
|
||||
float4 color = input.Sample(samplerState, tex);
|
||||
color += Blur(input, tex, SCALED_GAUSSIAN_SIGMA)*0.3;
|
||||
color = Scanline(color, pos);
|
||||
|
||||
return color;
|
||||
}
|
||||
@@ -11,6 +11,9 @@
|
||||
<Rule Id="C26466" Action="None" />
|
||||
<!-- This one has caught us off guard as it suddenly showed up. Re-enablement is going to be in #2941 -->
|
||||
<Rule Id="C26814" Action="None" />
|
||||
|
||||
<!-- There are *so many* enums that should be enum classes. -->
|
||||
<Rule Id="C26812" Action="None" />
|
||||
</Rules>
|
||||
|
||||
|
||||
|
||||
@@ -11,10 +11,16 @@
|
||||
// - attr - the default text attribute
|
||||
// Return Value:
|
||||
// - constructed object
|
||||
// Note: will throw exception if unable to allocate memory for text attribute storage
|
||||
ATTR_ROW::ATTR_ROW(const UINT cchRowWidth, const TextAttribute attr)
|
||||
ATTR_ROW::ATTR_ROW(const UINT cchRowWidth, const TextAttribute attr) noexcept
|
||||
{
|
||||
_list.push_back(TextAttributeRun(cchRowWidth, attr));
|
||||
try
|
||||
{
|
||||
_list.emplace_back(TextAttributeRun(cchRowWidth, attr));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
FAIL_FAST_CAUGHT_EXCEPTION();
|
||||
}
|
||||
_cchRowWidth = cchRowWidth;
|
||||
}
|
||||
|
||||
@@ -25,7 +31,7 @@ ATTR_ROW::ATTR_ROW(const UINT cchRowWidth, const TextAttribute attr)
|
||||
void ATTR_ROW::Reset(const TextAttribute attr)
|
||||
{
|
||||
_list.clear();
|
||||
_list.push_back(TextAttributeRun(_cchRowWidth, attr));
|
||||
_list.emplace_back(TextAttributeRun(_cchRowWidth, attr));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -178,15 +184,15 @@ size_t ATTR_ROW::FindAttrIndex(const size_t index, size_t* const pApplies) const
|
||||
// Routine Description:
|
||||
// - Finds the hyperlink IDs present in this row and returns them
|
||||
// Return value:
|
||||
// - An unordered set containing the hyperlink IDs present in this row
|
||||
std::unordered_set<uint16_t> ATTR_ROW::GetHyperlinks()
|
||||
// - The hyperlink IDs present in this row
|
||||
std::vector<uint16_t> ATTR_ROW::GetHyperlinks()
|
||||
{
|
||||
std::unordered_set<uint16_t> ids;
|
||||
std::vector<uint16_t> ids;
|
||||
for (const auto& run : _list)
|
||||
{
|
||||
if (run.GetAttributes().IsHyperlink())
|
||||
{
|
||||
ids.emplace(run.GetAttributes().GetHyperlinkId());
|
||||
ids.emplace_back(run.GetAttributes().GetHyperlinkId());
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
@@ -402,7 +408,7 @@ void ATTR_ROW::ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAtt
|
||||
// The original run was 3 long. The insertion run was 1 long. We need 1 more for the
|
||||
// fact that an existing piece of the run was split in half (to hold the latter half).
|
||||
const size_t cNewRun = _list.size() + newAttrs.size() + 1;
|
||||
std::vector<TextAttributeRun> newRun;
|
||||
decltype(_list) newRun;
|
||||
newRun.reserve(cNewRun);
|
||||
|
||||
// We will start analyzing from the beginning of our existing run.
|
||||
@@ -595,8 +601,7 @@ std::vector<TextAttributeRun> ATTR_ROW::PackAttrs(const std::vector<TextAttribut
|
||||
{
|
||||
if (runs.empty() || runs.back().GetAttributes() != attr)
|
||||
{
|
||||
const TextAttributeRun run(1, attr);
|
||||
runs.push_back(run);
|
||||
runs.emplace_back(TextAttributeRun(1, attr));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -28,7 +28,16 @@ class ATTR_ROW final
|
||||
public:
|
||||
using const_iterator = typename AttrRowIterator;
|
||||
|
||||
ATTR_ROW(const UINT cchRowWidth, const TextAttribute attr);
|
||||
ATTR_ROW(const UINT cchRowWidth, const TextAttribute attr)
|
||||
noexcept;
|
||||
|
||||
~ATTR_ROW() = default;
|
||||
|
||||
ATTR_ROW(const ATTR_ROW&) = default;
|
||||
ATTR_ROW& operator=(const ATTR_ROW&) = default;
|
||||
ATTR_ROW(ATTR_ROW&&)
|
||||
noexcept = default;
|
||||
ATTR_ROW& operator=(ATTR_ROW&&) noexcept = default;
|
||||
|
||||
void Reset(const TextAttribute attr);
|
||||
|
||||
@@ -41,7 +50,7 @@ public:
|
||||
size_t FindAttrIndex(const size_t index,
|
||||
size_t* const pApplies) const;
|
||||
|
||||
std::unordered_set<uint16_t> GetHyperlinks();
|
||||
std::vector<uint16_t> GetHyperlinks();
|
||||
|
||||
bool SetAttrToEnd(const UINT iStart, const TextAttribute attr);
|
||||
void ReplaceAttrs(const TextAttribute& toBeReplacedAttr, const TextAttribute& replaceWith) noexcept;
|
||||
@@ -65,7 +74,7 @@ public:
|
||||
friend class AttrRowIterator;
|
||||
|
||||
private:
|
||||
std::vector<TextAttributeRun> _list;
|
||||
boost::container::small_vector<TextAttributeRun, 1> _list;
|
||||
size_t _cchRowWidth;
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
|
||||
@@ -21,12 +21,12 @@ AttrRowIterator::AttrRowIterator(const ATTR_ROW* const attrRow) noexcept :
|
||||
{
|
||||
}
|
||||
|
||||
AttrRowIterator::operator bool() const
|
||||
AttrRowIterator::operator bool() const noexcept
|
||||
{
|
||||
return !_exceeded && _run < _pAttrRow->_list.cend();
|
||||
}
|
||||
|
||||
bool AttrRowIterator::operator==(const AttrRowIterator& it) const
|
||||
bool AttrRowIterator::operator==(const AttrRowIterator& it) const noexcept
|
||||
{
|
||||
return (_pAttrRow == it._pAttrRow &&
|
||||
_run == it._run &&
|
||||
@@ -34,24 +34,11 @@ bool AttrRowIterator::operator==(const AttrRowIterator& it) const
|
||||
_exceeded == it._exceeded);
|
||||
}
|
||||
|
||||
bool AttrRowIterator::operator!=(const AttrRowIterator& it) const
|
||||
bool AttrRowIterator::operator!=(const AttrRowIterator& it) const noexcept
|
||||
{
|
||||
return !(*this == it);
|
||||
}
|
||||
|
||||
AttrRowIterator& AttrRowIterator::operator++()
|
||||
{
|
||||
_increment(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AttrRowIterator AttrRowIterator::operator++(int)
|
||||
{
|
||||
auto copy = *this;
|
||||
_increment(1);
|
||||
return copy;
|
||||
}
|
||||
|
||||
AttrRowIterator& AttrRowIterator::operator+=(const ptrdiff_t& movement)
|
||||
{
|
||||
if (!_exceeded)
|
||||
@@ -74,19 +61,6 @@ AttrRowIterator& AttrRowIterator::operator-=(const ptrdiff_t& movement)
|
||||
return this->operator+=(-movement);
|
||||
}
|
||||
|
||||
AttrRowIterator& AttrRowIterator::operator--()
|
||||
{
|
||||
_decrement(1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AttrRowIterator AttrRowIterator::operator--(int)
|
||||
{
|
||||
auto copy = *this;
|
||||
_decrement(1);
|
||||
return copy;
|
||||
}
|
||||
|
||||
const TextAttribute* AttrRowIterator::operator->() const
|
||||
{
|
||||
THROW_HR_IF(E_BOUNDS, _exceeded);
|
||||
@@ -103,7 +77,7 @@ const TextAttribute& AttrRowIterator::operator*() const
|
||||
// - increments the index the iterator points to
|
||||
// Arguments:
|
||||
// - count - the amount to increment by
|
||||
void AttrRowIterator::_increment(size_t count)
|
||||
void AttrRowIterator::_increment(size_t count) noexcept
|
||||
{
|
||||
while (count > 0)
|
||||
{
|
||||
@@ -126,7 +100,7 @@ void AttrRowIterator::_increment(size_t count)
|
||||
// - decrements the index the iterator points to
|
||||
// Arguments:
|
||||
// - count - the amount to decrement by
|
||||
void AttrRowIterator::_decrement(size_t count)
|
||||
void AttrRowIterator::_decrement(size_t count) noexcept
|
||||
{
|
||||
while (count > 0)
|
||||
{
|
||||
|
||||
@@ -33,30 +33,48 @@ public:
|
||||
|
||||
AttrRowIterator(const ATTR_ROW* const attrRow) noexcept;
|
||||
|
||||
operator bool() const;
|
||||
operator bool() const noexcept;
|
||||
|
||||
bool operator==(const AttrRowIterator& it) const;
|
||||
bool operator!=(const AttrRowIterator& it) const;
|
||||
bool operator==(const AttrRowIterator& it) const noexcept;
|
||||
bool operator!=(const AttrRowIterator& it) const noexcept;
|
||||
|
||||
AttrRowIterator& operator++();
|
||||
AttrRowIterator operator++(int);
|
||||
AttrRowIterator& operator++() noexcept
|
||||
{
|
||||
_increment(1);
|
||||
return *this;
|
||||
}
|
||||
AttrRowIterator operator++(int) noexcept
|
||||
{
|
||||
auto copy = *this;
|
||||
_increment(1);
|
||||
return copy;
|
||||
}
|
||||
|
||||
AttrRowIterator& operator+=(const ptrdiff_t& movement);
|
||||
AttrRowIterator& operator-=(const ptrdiff_t& movement);
|
||||
|
||||
AttrRowIterator& operator--();
|
||||
AttrRowIterator operator--(int);
|
||||
AttrRowIterator& operator--() noexcept
|
||||
{
|
||||
_decrement(1);
|
||||
return *this;
|
||||
}
|
||||
AttrRowIterator operator--(int) noexcept
|
||||
{
|
||||
auto copy = *this;
|
||||
_decrement(1);
|
||||
return copy;
|
||||
}
|
||||
|
||||
const TextAttribute* operator->() const;
|
||||
const TextAttribute& operator*() const;
|
||||
|
||||
private:
|
||||
std::vector<TextAttributeRun>::const_iterator _run;
|
||||
boost::container::small_vector_base<TextAttributeRun>::const_iterator _run;
|
||||
const ATTR_ROW* _pAttrRow;
|
||||
size_t _currentAttributeIndex; // index of TextAttribute within the current TextAttributeRun
|
||||
bool _exceeded;
|
||||
|
||||
void _increment(size_t count);
|
||||
void _decrement(size_t count);
|
||||
void _increment(size_t count) noexcept;
|
||||
void _decrement(size_t count) noexcept;
|
||||
void _setToEnd() noexcept;
|
||||
};
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
// Return Value:
|
||||
// - instantiated object
|
||||
// Note: will through if unable to allocate char/attribute buffers
|
||||
CharRow::CharRow(size_t rowWidth, ROW* const pParent) :
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26447) // small_vector's constructor says it can throw but it should not given how we use it. This suppresses this error for the AuditMode build.
|
||||
CharRow::CharRow(size_t rowWidth, ROW* const pParent) noexcept :
|
||||
_wrapForced{ false },
|
||||
_doubleBytePadded{ false },
|
||||
_data(rowWidth, value_type()),
|
||||
_pParent{ FAIL_FAST_IF_NULL(pParent) }
|
||||
{
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
// Routine Description:
|
||||
// - Sets the wrap status for the current row
|
||||
@@ -139,9 +142,9 @@ typename CharRow::const_iterator CharRow::cend() const noexcept
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The calculated left boundary of the internal string.
|
||||
size_t CharRow::MeasureLeft() const
|
||||
size_t CharRow::MeasureLeft() const noexcept
|
||||
{
|
||||
std::vector<value_type>::const_iterator it = _data.cbegin();
|
||||
const_iterator it = _data.cbegin();
|
||||
while (it != _data.cend() && it->IsSpace())
|
||||
{
|
||||
++it;
|
||||
@@ -155,9 +158,9 @@ size_t CharRow::MeasureLeft() const
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - The calculated right boundary of the internal string.
|
||||
size_t CharRow::MeasureRight() const noexcept
|
||||
size_t CharRow::MeasureRight() const
|
||||
{
|
||||
std::vector<value_type>::const_reverse_iterator it = _data.crbegin();
|
||||
const_reverse_iterator it = _data.crbegin();
|
||||
while (it != _data.crend() && it->IsSpace())
|
||||
{
|
||||
++it;
|
||||
|
||||
@@ -49,11 +49,12 @@ class CharRow final
|
||||
public:
|
||||
using glyph_type = typename wchar_t;
|
||||
using value_type = typename CharRowCell;
|
||||
using iterator = typename std::vector<value_type>::iterator;
|
||||
using const_iterator = typename std::vector<value_type>::const_iterator;
|
||||
using iterator = typename boost::container::small_vector_base<value_type>::iterator;
|
||||
using const_iterator = typename boost::container::small_vector_base<value_type>::const_iterator;
|
||||
using const_reverse_iterator = typename boost::container::small_vector_base<value_type>::const_reverse_iterator;
|
||||
using reference = typename CharRowCellReference;
|
||||
|
||||
CharRow(size_t rowWidth, ROW* const pParent);
|
||||
CharRow(size_t rowWidth, ROW* const pParent) noexcept;
|
||||
|
||||
void SetWrapForced(const bool wrap) noexcept;
|
||||
bool WasWrapForced() const noexcept;
|
||||
@@ -62,8 +63,8 @@ public:
|
||||
size_t size() const noexcept;
|
||||
void Reset() noexcept;
|
||||
[[nodiscard]] HRESULT Resize(const size_t newSize) noexcept;
|
||||
size_t MeasureLeft() const;
|
||||
size_t MeasureRight() const noexcept;
|
||||
size_t MeasureLeft() const noexcept;
|
||||
size_t MeasureRight() const;
|
||||
void ClearCell(const size_t column);
|
||||
bool ContainsText() const noexcept;
|
||||
const DbcsAttribute& DbcsAttrAt(const size_t column) const;
|
||||
@@ -101,7 +102,7 @@ protected:
|
||||
bool _doubleBytePadded;
|
||||
|
||||
// storage for glyph data and dbcs attributes
|
||||
std::vector<value_type> _data;
|
||||
boost::container::small_vector<value_type, 120> _data;
|
||||
|
||||
// ROW that this CharRow belongs to
|
||||
ROW* _pParent;
|
||||
|
||||
@@ -8,18 +8,6 @@
|
||||
// default glyph value, used for resetting the character data portion of a cell
|
||||
static constexpr wchar_t DefaultValue = UNICODE_SPACE;
|
||||
|
||||
CharRowCell::CharRowCell() noexcept :
|
||||
_wch{ DefaultValue },
|
||||
_attr{}
|
||||
{
|
||||
}
|
||||
|
||||
CharRowCell::CharRowCell(const wchar_t wch, const DbcsAttribute attr) noexcept :
|
||||
_wch{ wch },
|
||||
_attr{ attr }
|
||||
{
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - "erases" the glyph. really sets it back to the default "empty" value
|
||||
void CharRowCell::EraseChars() noexcept
|
||||
|
||||
@@ -17,6 +17,7 @@ Author(s):
|
||||
#pragma once
|
||||
|
||||
#include "DbcsAttribute.hpp"
|
||||
#include "unicode.hpp"
|
||||
|
||||
#if (defined(_M_IX86) || defined(_M_AMD64))
|
||||
// currently CharRowCell's fields use 3 bytes of memory, leaving the 4th byte in unused. this leads
|
||||
@@ -27,8 +28,13 @@ Author(s):
|
||||
class CharRowCell final
|
||||
{
|
||||
public:
|
||||
CharRowCell() noexcept;
|
||||
CharRowCell(const wchar_t wch, const DbcsAttribute attr) noexcept;
|
||||
CharRowCell() noexcept = default;
|
||||
CharRowCell(const wchar_t wch, const DbcsAttribute attr) noexcept
|
||||
:
|
||||
_wch(wch),
|
||||
_attr(attr)
|
||||
{
|
||||
}
|
||||
|
||||
void EraseChars() noexcept;
|
||||
void Reset() noexcept;
|
||||
@@ -44,8 +50,8 @@ public:
|
||||
friend constexpr bool operator==(const CharRowCell& a, const CharRowCell& b) noexcept;
|
||||
|
||||
private:
|
||||
wchar_t _wch;
|
||||
DbcsAttribute _attr;
|
||||
wchar_t _wch{ UNICODE_SPACE };
|
||||
DbcsAttribute _attr{};
|
||||
};
|
||||
|
||||
#if (defined(_M_IX86) || defined(_M_AMD64))
|
||||
|
||||
@@ -32,8 +32,8 @@ public:
|
||||
}
|
||||
|
||||
~CharRowCellReference() = default;
|
||||
CharRowCellReference(const CharRowCellReference&) = default;
|
||||
CharRowCellReference(CharRowCellReference&&) = default;
|
||||
CharRowCellReference(const CharRowCellReference&) noexcept = default;
|
||||
CharRowCellReference(CharRowCellReference&&) noexcept = default;
|
||||
|
||||
void operator=(const CharRowCellReference&) = delete;
|
||||
void operator=(CharRowCellReference&&) = delete;
|
||||
|
||||
@@ -16,50 +16,15 @@
|
||||
// - pParent - the text buffer that this row belongs to
|
||||
// Return Value:
|
||||
// - constructed object
|
||||
ROW::ROW(const SHORT rowId, const short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent) :
|
||||
ROW::ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent) noexcept :
|
||||
_id{ rowId },
|
||||
_rowWidth{ gsl::narrow<size_t>(rowWidth) },
|
||||
_charRow{ gsl::narrow<size_t>(rowWidth), this },
|
||||
_attrRow{ gsl::narrow<UINT>(rowWidth), fillAttribute },
|
||||
_rowWidth{ rowWidth },
|
||||
_charRow{ rowWidth, this },
|
||||
_attrRow{ rowWidth, fillAttribute },
|
||||
_pParent{ pParent }
|
||||
{
|
||||
}
|
||||
|
||||
size_t ROW::size() const noexcept
|
||||
{
|
||||
return _rowWidth;
|
||||
}
|
||||
|
||||
const CharRow& ROW::GetCharRow() const noexcept
|
||||
{
|
||||
return _charRow;
|
||||
}
|
||||
|
||||
CharRow& ROW::GetCharRow() noexcept
|
||||
{
|
||||
return _charRow;
|
||||
}
|
||||
|
||||
const ATTR_ROW& ROW::GetAttrRow() const noexcept
|
||||
{
|
||||
return _attrRow;
|
||||
}
|
||||
|
||||
ATTR_ROW& ROW::GetAttrRow() noexcept
|
||||
{
|
||||
return _attrRow;
|
||||
}
|
||||
|
||||
SHORT ROW::GetId() const noexcept
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
void ROW::SetId(const SHORT id) noexcept
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Sets all properties of the ROW to default values
|
||||
// Arguments:
|
||||
@@ -87,7 +52,7 @@ bool ROW::Reset(const TextAttribute Attr)
|
||||
// - width - the new width, in cells
|
||||
// Return Value:
|
||||
// - S_OK if successful, otherwise relevant error
|
||||
[[nodiscard]] HRESULT ROW::Resize(const size_t width)
|
||||
[[nodiscard]] HRESULT ROW::Resize(const unsigned short width)
|
||||
{
|
||||
RETURN_IF_FAILED(_charRow.Resize(width));
|
||||
try
|
||||
@@ -113,25 +78,6 @@ void ROW::ClearColumn(const size_t column)
|
||||
_charRow.ClearCell(column);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - gets the text of the row as it would be shown on the screen
|
||||
// Return Value:
|
||||
// - wstring containing text for the row
|
||||
std::wstring ROW::GetText() const
|
||||
{
|
||||
return _charRow.GetText();
|
||||
}
|
||||
|
||||
RowCellIterator ROW::AsCellIter(const size_t startIndex) const
|
||||
{
|
||||
return AsCellIter(startIndex, size() - startIndex);
|
||||
}
|
||||
|
||||
RowCellIterator ROW::AsCellIter(const size_t startIndex, const size_t count) const
|
||||
{
|
||||
return RowCellIterator(*this, startIndex, count);
|
||||
}
|
||||
|
||||
UnicodeStorage& ROW::GetUnicodeStorage() noexcept
|
||||
{
|
||||
return _pParent->GetUnicodeStorage();
|
||||
|
||||
@@ -32,27 +32,28 @@ class TextBuffer;
|
||||
class ROW final
|
||||
{
|
||||
public:
|
||||
ROW(const SHORT rowId, const short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent);
|
||||
ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent)
|
||||
noexcept;
|
||||
|
||||
size_t size() const noexcept;
|
||||
size_t size() const noexcept { return _rowWidth; }
|
||||
|
||||
const CharRow& GetCharRow() const noexcept;
|
||||
CharRow& GetCharRow() noexcept;
|
||||
const CharRow& GetCharRow() const noexcept { return _charRow; }
|
||||
CharRow& GetCharRow() noexcept { return _charRow; }
|
||||
|
||||
const ATTR_ROW& GetAttrRow() const noexcept;
|
||||
ATTR_ROW& GetAttrRow() noexcept;
|
||||
const ATTR_ROW& GetAttrRow() const noexcept { return _attrRow; }
|
||||
ATTR_ROW& GetAttrRow() noexcept { return _attrRow; }
|
||||
|
||||
SHORT GetId() const noexcept;
|
||||
void SetId(const SHORT id) noexcept;
|
||||
SHORT GetId() const noexcept { return _id; }
|
||||
void SetId(const SHORT id) noexcept { _id = id; }
|
||||
|
||||
bool Reset(const TextAttribute Attr);
|
||||
[[nodiscard]] HRESULT Resize(const size_t width);
|
||||
[[nodiscard]] HRESULT Resize(const unsigned short width);
|
||||
|
||||
void ClearColumn(const size_t column);
|
||||
std::wstring GetText() const;
|
||||
std::wstring GetText() const { return _charRow.GetText(); }
|
||||
|
||||
RowCellIterator AsCellIter(const size_t startIndex) const;
|
||||
RowCellIterator AsCellIter(const size_t startIndex, const size_t count) const;
|
||||
RowCellIterator AsCellIter(const size_t startIndex) const { return AsCellIter(startIndex, size() - startIndex); }
|
||||
RowCellIterator AsCellIter(const size_t startIndex, const size_t count) const { return RowCellIterator(*this, startIndex, count); }
|
||||
|
||||
UnicodeStorage& GetUnicodeStorage() noexcept;
|
||||
const UnicodeStorage& GetUnicodeStorage() const noexcept;
|
||||
@@ -69,7 +70,7 @@ private:
|
||||
CharRow _charRow;
|
||||
ATTR_ROW _attrRow;
|
||||
SHORT _id;
|
||||
size_t _rowWidth;
|
||||
unsigned short _rowWidth;
|
||||
TextBuffer* _pParent; // non ownership pointer
|
||||
};
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "TextAttributeRun.hpp"
|
||||
|
||||
TextAttributeRun::TextAttributeRun() noexcept :
|
||||
_cchLength(0)
|
||||
{
|
||||
SetAttributes(TextAttribute(0));
|
||||
}
|
||||
|
||||
TextAttributeRun::TextAttributeRun(const size_t cchLength, const TextAttribute attr) noexcept :
|
||||
_cchLength(cchLength)
|
||||
{
|
||||
SetAttributes(attr);
|
||||
}
|
||||
|
||||
size_t TextAttributeRun::GetLength() const noexcept
|
||||
{
|
||||
return _cchLength;
|
||||
}
|
||||
|
||||
void TextAttributeRun::SetLength(const size_t cchLength) noexcept
|
||||
{
|
||||
_cchLength = cchLength;
|
||||
}
|
||||
|
||||
void TextAttributeRun::IncrementLength() noexcept
|
||||
{
|
||||
_cchLength++;
|
||||
}
|
||||
|
||||
void TextAttributeRun::DecrementLength() noexcept
|
||||
{
|
||||
_cchLength--;
|
||||
}
|
||||
|
||||
const TextAttribute& TextAttributeRun::GetAttributes() const noexcept
|
||||
{
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
void TextAttributeRun::SetAttributes(const TextAttribute textAttribute) noexcept
|
||||
{
|
||||
_attributes = textAttribute;
|
||||
}
|
||||
@@ -25,20 +25,24 @@ Revision History:
|
||||
class TextAttributeRun final
|
||||
{
|
||||
public:
|
||||
TextAttributeRun() noexcept;
|
||||
TextAttributeRun(const size_t cchLength, const TextAttribute attr) noexcept;
|
||||
TextAttributeRun() = default;
|
||||
TextAttributeRun(const size_t cchLength, const TextAttribute attr) noexcept :
|
||||
_cchLength(gsl::narrow<unsigned int>(cchLength))
|
||||
{
|
||||
SetAttributes(attr);
|
||||
}
|
||||
|
||||
size_t GetLength() const noexcept;
|
||||
void SetLength(const size_t cchLength) noexcept;
|
||||
void IncrementLength() noexcept;
|
||||
void DecrementLength() noexcept;
|
||||
size_t GetLength() const noexcept { return _cchLength; }
|
||||
void SetLength(const size_t cchLength) noexcept { _cchLength = gsl::narrow<unsigned int>(cchLength); }
|
||||
void IncrementLength() noexcept { _cchLength++; }
|
||||
void DecrementLength() noexcept { _cchLength--; }
|
||||
|
||||
const TextAttribute& GetAttributes() const noexcept;
|
||||
void SetAttributes(const TextAttribute textAttribute) noexcept;
|
||||
const TextAttribute& GetAttributes() const noexcept { return _attributes; }
|
||||
void SetAttributes(const TextAttribute textAttribute) noexcept { _attributes = textAttribute; }
|
||||
|
||||
private:
|
||||
size_t _cchLength;
|
||||
TextAttribute _attributes;
|
||||
unsigned int _cchLength{ 0 };
|
||||
TextAttribute _attributes{ 0 };
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class AttrRowTests;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>bufferout</RootNamespace>
|
||||
<ProjectName>BufferOut</ProjectName>
|
||||
<TargetName>ConBufferOut</TargetName>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)src\common.build.pre.props" />
|
||||
<ItemGroup>
|
||||
@@ -22,7 +22,6 @@
|
||||
<ClCompile Include="..\search.cpp" />
|
||||
<ClCompile Include="..\TextColor.cpp" />
|
||||
<ClCompile Include="..\TextAttribute.cpp" />
|
||||
<ClCompile Include="..\TextAttributeRun.cpp" />
|
||||
<ClCompile Include="..\textBuffer.cpp" />
|
||||
<ClCompile Include="..\textBufferCellIterator.cpp" />
|
||||
<ClCompile Include="..\textBufferTextIterator.cpp" />
|
||||
@@ -61,4 +60,4 @@
|
||||
</ItemGroup>
|
||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -25,6 +25,9 @@ Abstract:
|
||||
#pragma warning(push)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
#endif
|
||||
|
||||
// Windows Header Files:
|
||||
|
||||
@@ -40,7 +40,6 @@ SOURCES= \
|
||||
..\RowCellIterator.cpp \
|
||||
..\TextColor.cpp \
|
||||
..\TextAttribute.cpp \
|
||||
..\TextAttributeRun.cpp \
|
||||
..\textBuffer.cpp \
|
||||
..\textBufferCellIterator.cpp \
|
||||
..\textBufferTextIterator.cpp \
|
||||
|
||||
@@ -42,6 +42,7 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
|
||||
_currentPatternId{ 0 }
|
||||
{
|
||||
// initialize ROWs
|
||||
_storage.reserve(static_cast<size_t>(screenBufferSize.Y));
|
||||
for (size_t i = 0; i < static_cast<size_t>(screenBufferSize.Y); ++i)
|
||||
{
|
||||
_storage.emplace_back(static_cast<SHORT>(i), screenBufferSize.X, _currentAttributes, this);
|
||||
@@ -837,11 +838,10 @@ void TextBuffer::Reset()
|
||||
const SHORT TopRowIndex = (GetFirstRowIndex() + TopRow) % currentSize.Y;
|
||||
|
||||
// rotate rows until the top row is at index 0
|
||||
const ROW& newTopRow = _storage.at(TopRowIndex);
|
||||
while (&newTopRow != &_storage.front())
|
||||
for (int i = 0; i < TopRowIndex; i++)
|
||||
{
|
||||
_storage.push_back(std::move(_storage.front()));
|
||||
_storage.pop_front();
|
||||
_storage.emplace_back(std::move(_storage.front()));
|
||||
_storage.erase(_storage.begin());
|
||||
}
|
||||
|
||||
_SetFirstRowIndex(0);
|
||||
@@ -1230,9 +1230,15 @@ void TextBuffer::_PruneHyperlinks()
|
||||
// If the buffer does not contain the same reference, we can remove that hyperlink from our map
|
||||
// This way, obsolete hyperlink references are cleared from our hyperlink map instead of hanging around
|
||||
// Get all the hyperlink references in the row we're erasing
|
||||
auto firstRowRefs = _storage.at(_firstRow).GetAttrRow().GetHyperlinks();
|
||||
if (!firstRowRefs.empty())
|
||||
const auto hyperlinks = _storage.at(_firstRow).GetAttrRow().GetHyperlinks();
|
||||
|
||||
if (!hyperlinks.empty())
|
||||
{
|
||||
// Move to unordered set so we can use hashed lookup of IDs instead of linear search.
|
||||
// Only make it an unordered set now because set always heap allocates but vector
|
||||
// doesn't when the set is empty (saving an allocation in the common case of no links.)
|
||||
std::unordered_set<uint16_t> firstRowRefs{ hyperlinks.cbegin(), hyperlinks.cend() };
|
||||
|
||||
const auto total = TotalRowCount();
|
||||
// Loop through all the rows in the buffer except the first row -
|
||||
// we have found all hyperlink references in the first row and put them in refs,
|
||||
@@ -1254,12 +1260,12 @@ void TextBuffer::_PruneHyperlinks()
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now delete obsolete references from our map
|
||||
for (auto hyperlinkReference : firstRowRefs)
|
||||
{
|
||||
RemoveHyperlinkFromMap(hyperlinkReference);
|
||||
// Now delete obsolete references from our map
|
||||
for (auto hyperlinkReference : firstRowRefs)
|
||||
{
|
||||
RemoveHyperlinkFromMap(hyperlinkReference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1512,12 +1518,14 @@ void TextBuffer::_ExpandTextRow(SMALL_RECT& textRow) const
|
||||
// - trimTrailingWhitespace - remove the trailing whitespace at the end of each line
|
||||
// - textRects - the rectangular regions from which the data will be extracted from the buffer (i.e.: selection rects)
|
||||
// - GetAttributeColors - function used to map TextAttribute to RGB COLORREFs. If null, only extract the text.
|
||||
// - formatWrappedRows - if set we will apply formatting (CRLF inclusion and whitespace trimming) on wrapped rows
|
||||
// Return Value:
|
||||
// - The text, background color, and foreground color data of the selected region of the text buffer.
|
||||
const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
|
||||
const bool trimTrailingWhitespace,
|
||||
const std::vector<SMALL_RECT>& selectionRects,
|
||||
std::function<std::pair<COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors) const
|
||||
std::function<std::pair<COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors,
|
||||
const bool formatWrappedRows) const
|
||||
{
|
||||
TextAndColor data;
|
||||
const bool copyTextColor = GetAttributeColors != nullptr;
|
||||
@@ -1579,12 +1587,12 @@ const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
|
||||
it++;
|
||||
}
|
||||
|
||||
const bool forcedWrap = GetRowByOffset(iRow).GetCharRow().WasWrapForced();
|
||||
// We apply formatting to rows if the row was NOT wrapped or formatting of wrapped rows is allowed
|
||||
const bool shouldFormatRow = formatWrappedRows || !GetRowByOffset(iRow).GetCharRow().WasWrapForced();
|
||||
|
||||
if (trimTrailingWhitespace)
|
||||
{
|
||||
// if the row was NOT wrapped...
|
||||
if (!forcedWrap)
|
||||
if (shouldFormatRow)
|
||||
{
|
||||
// remove the spaces at the end (aka trim the trailing whitespace)
|
||||
while (!selectionText.empty() && selectionText.back() == UNICODE_SPACE)
|
||||
@@ -1603,8 +1611,7 @@ const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
|
||||
// a.k.a if we're earlier than the bottom, then apply CR/LF.
|
||||
if (includeCRLF && i < selectionRects.size() - 1)
|
||||
{
|
||||
// if the row was NOT wrapped...
|
||||
if (!forcedWrap)
|
||||
if (shouldFormatRow)
|
||||
{
|
||||
// then we can assume a CR/LF is proper
|
||||
selectionText.push_back(UNICODE_CARRIAGERETURN);
|
||||
@@ -2322,7 +2329,7 @@ uint16_t TextBuffer::GetHyperlinkId(std::wstring_view uri, std::wstring_view id)
|
||||
// user defined id from the custom id map (if there is one)
|
||||
// Arguments:
|
||||
// - The ID of the hyperlink to be removed
|
||||
void TextBuffer::RemoveHyperlinkFromMap(uint16_t id)
|
||||
void TextBuffer::RemoveHyperlinkFromMap(uint16_t id) noexcept
|
||||
{
|
||||
_hyperlinkMap.erase(id);
|
||||
for (const auto& customIdPair : _hyperlinkCustomIdMap)
|
||||
@@ -2409,7 +2416,7 @@ PointTree TextBuffer::GetPatterns(const size_t firstRow, const size_t lastRow) c
|
||||
// all the text into one string and find the patterns in that string
|
||||
for (auto i = firstRow; i <= lastRow; ++i)
|
||||
{
|
||||
auto row = GetRowByOffset(i);
|
||||
auto& row = GetRowByOffset(i);
|
||||
concatAll += row.GetCharRow().GetText();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ filling in the last row, and updating the screen.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "cursor.h"
|
||||
#include "Row.hpp"
|
||||
#include "TextAttribute.hpp"
|
||||
@@ -144,7 +146,7 @@ public:
|
||||
void AddHyperlinkToMap(std::wstring_view uri, uint16_t id);
|
||||
std::wstring GetHyperlinkUriFromId(uint16_t id) const;
|
||||
uint16_t GetHyperlinkId(std::wstring_view uri, std::wstring_view id);
|
||||
void RemoveHyperlinkFromMap(uint16_t id);
|
||||
void RemoveHyperlinkFromMap(uint16_t id) noexcept;
|
||||
std::wstring GetCustomIdFromId(uint16_t id) const;
|
||||
void CopyHyperlinkMaps(const TextBuffer& OtherBuffer);
|
||||
|
||||
@@ -156,10 +158,11 @@ public:
|
||||
std::vector<std::vector<COLORREF>> BkAttr;
|
||||
};
|
||||
|
||||
const TextAndColor GetText(const bool lineSelection,
|
||||
const TextAndColor GetText(const bool includeCRLF,
|
||||
const bool trimTrailingWhitespace,
|
||||
const std::vector<SMALL_RECT>& textRects,
|
||||
std::function<std::pair<COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors = nullptr) const;
|
||||
std::function<std::pair<COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors = nullptr,
|
||||
const bool formatWrappedRows = false) const;
|
||||
|
||||
static std::string GenHTML(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
@@ -189,7 +192,7 @@ public:
|
||||
private:
|
||||
void _UpdateSize();
|
||||
Microsoft::Console::Types::Viewport _size;
|
||||
std::deque<ROW> _storage;
|
||||
std::vector<ROW> _storage;
|
||||
Cursor _cursor;
|
||||
|
||||
SHORT _firstRow; // indexes top row (not necessarily 0)
|
||||
|
||||
@@ -65,7 +65,7 @@ TextBufferCellIterator::operator bool() const noexcept
|
||||
// - it - The other iterator to compare to this one.
|
||||
// Return Value:
|
||||
// - True if it's the same text buffer and same cell position. False otherwise.
|
||||
bool TextBufferCellIterator::operator==(const TextBufferCellIterator& it) const
|
||||
bool TextBufferCellIterator::operator==(const TextBufferCellIterator& it) const noexcept
|
||||
{
|
||||
return _pos == it._pos &&
|
||||
&_buffer == &it._buffer &&
|
||||
@@ -81,7 +81,7 @@ bool TextBufferCellIterator::operator==(const TextBufferCellIterator& it) const
|
||||
// - it - The other iterator to compare to this one.
|
||||
// Return Value:
|
||||
// - True if it's the same text buffer and different cell position or if they're different buffers. False otherwise.
|
||||
bool TextBufferCellIterator::operator!=(const TextBufferCellIterator& it) const
|
||||
bool TextBufferCellIterator::operator!=(const TextBufferCellIterator& it) const noexcept
|
||||
{
|
||||
return !(*this == it);
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ public:
|
||||
|
||||
operator bool() const noexcept;
|
||||
|
||||
bool operator==(const TextBufferCellIterator& it) const;
|
||||
bool operator!=(const TextBufferCellIterator& it) const;
|
||||
bool operator==(const TextBufferCellIterator& it) const noexcept;
|
||||
bool operator!=(const TextBufferCellIterator& it) const noexcept;
|
||||
|
||||
TextBufferCellIterator& operator+=(const ptrdiff_t& movement);
|
||||
TextBufferCellIterator& operator-=(const ptrdiff_t& movement);
|
||||
|
||||
@@ -26,6 +26,9 @@ Abstract:
|
||||
#pragma warning(disable: ALL_CPPCORECHECK_WARNINGS)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
#endif
|
||||
|
||||
// Windows Header Files:
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace SettingsModelLocalTests
|
||||
TEST_METHOD(ManyCommandsSameAction);
|
||||
TEST_METHOD(LayerCommand);
|
||||
TEST_METHOD(TestSplitPaneArgs);
|
||||
TEST_METHOD(TestSplitPaneBadSize);
|
||||
TEST_METHOD(TestResourceKeyName);
|
||||
TEST_METHOD(TestAutogeneratedName);
|
||||
TEST_METHOD(TestLayerOnAutogeneratedName);
|
||||
@@ -147,7 +148,8 @@ namespace SettingsModelLocalTests
|
||||
{ "name": "command1", "command": { "action": "splitPane", "split": "vertical" } },
|
||||
{ "name": "command2", "command": { "action": "splitPane", "split": "horizontal" } },
|
||||
{ "name": "command4", "command": { "action": "splitPane" } },
|
||||
{ "name": "command5", "command": { "action": "splitPane", "split": "auto" } }
|
||||
{ "name": "command5", "command": { "action": "splitPane", "split": "auto" } },
|
||||
{ "name": "command6", "command": { "action": "splitPane", "size": 0.25 } },
|
||||
])" };
|
||||
|
||||
const auto commands0Json = VerifyParseSucceeded(commands0String);
|
||||
@@ -156,7 +158,7 @@ namespace SettingsModelLocalTests
|
||||
VERIFY_ARE_EQUAL(0u, commands.Size());
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
VERIFY_ARE_EQUAL(0u, warnings.size());
|
||||
VERIFY_ARE_EQUAL(4u, commands.Size());
|
||||
VERIFY_ARE_EQUAL(5u, commands.Size());
|
||||
|
||||
{
|
||||
auto command = commands.Lookup(L"command1");
|
||||
@@ -167,6 +169,7 @@ namespace SettingsModelLocalTests
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_ARE_EQUAL(SplitState::Vertical, realArgs.SplitStyle());
|
||||
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
|
||||
}
|
||||
{
|
||||
auto command = commands.Lookup(L"command2");
|
||||
@@ -177,6 +180,7 @@ namespace SettingsModelLocalTests
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_ARE_EQUAL(SplitState::Horizontal, realArgs.SplitStyle());
|
||||
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
|
||||
}
|
||||
{
|
||||
auto command = commands.Lookup(L"command4");
|
||||
@@ -187,6 +191,7 @@ namespace SettingsModelLocalTests
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
|
||||
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
|
||||
}
|
||||
{
|
||||
auto command = commands.Lookup(L"command5");
|
||||
@@ -197,8 +202,51 @@ namespace SettingsModelLocalTests
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
|
||||
VERIFY_ARE_EQUAL(0.5, realArgs.SplitSize());
|
||||
}
|
||||
{
|
||||
auto command = commands.Lookup(L"command6");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
VERIFY_IS_NOT_NULL(command.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
|
||||
const auto& realArgs = command.Action().Args().try_as<SplitPaneArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
|
||||
VERIFY_ARE_EQUAL(0.25, realArgs.SplitSize());
|
||||
}
|
||||
}
|
||||
|
||||
void CommandTests::TestSplitPaneBadSize()
|
||||
{
|
||||
const std::string commands0String{ R"([
|
||||
{ "name": "command1", "command": { "action": "splitPane", "size": 0.25 } },
|
||||
{ "name": "command2", "command": { "action": "splitPane", "size": 1.0 } },
|
||||
{ "name": "command3", "command": { "action": "splitPane", "size": 0 } },
|
||||
{ "name": "command4", "command": { "action": "splitPane", "size": 50 } },
|
||||
])" };
|
||||
|
||||
const auto commands0Json = VerifyParseSucceeded(commands0String);
|
||||
|
||||
IMap<winrt::hstring, Command> commands = winrt::single_threaded_map<winrt::hstring, Command>();
|
||||
VERIFY_ARE_EQUAL(0u, commands.Size());
|
||||
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
|
||||
VERIFY_ARE_EQUAL(3u, warnings.size());
|
||||
VERIFY_ARE_EQUAL(1u, commands.Size());
|
||||
|
||||
{
|
||||
auto command = commands.Lookup(L"command1");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
VERIFY_IS_NOT_NULL(command.Action());
|
||||
VERIFY_ARE_EQUAL(ShortcutAction::SplitPane, command.Action().Action());
|
||||
const auto& realArgs = command.Action().Args().try_as<SplitPaneArgs>();
|
||||
VERIFY_IS_NOT_NULL(realArgs);
|
||||
// Verify the args have the expected value
|
||||
VERIFY_ARE_EQUAL(SplitState::Automatic, realArgs.SplitStyle());
|
||||
VERIFY_ARE_EQUAL(0.25, realArgs.SplitSize());
|
||||
}
|
||||
}
|
||||
|
||||
void CommandTests::TestResourceKeyName()
|
||||
{
|
||||
// This test checks looking up a name from a resource key.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "../TerminalApp/TerminalSettings.h"
|
||||
#include "../TerminalApp/CommandLinePaletteItem.h"
|
||||
#include "../TerminalApp/CommandPalette.h"
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
@@ -29,32 +29,10 @@ namespace TerminalAppLocalTests
|
||||
|
||||
void FilteredCommandTests::VerifyHighlighting()
|
||||
{
|
||||
const std::string settingsJson{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{ "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" }, "name": "AAAAAABBBBBBCCC" }
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
const auto commands = settings.GlobalSettings().Commands();
|
||||
VERIFY_ARE_EQUAL(1u, commands.Size());
|
||||
|
||||
const auto command = commands.Lookup(L"AAAAAABBBBBBCCC");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
VERIFY_ARE_EQUAL(command.Name(), L"AAAAAABBBBBBCCC");
|
||||
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
|
||||
{
|
||||
Log::Comment(L"Testing command name segmentation with no filter");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
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");
|
||||
@@ -62,7 +40,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing command name segmentation with empty filter");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
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);
|
||||
@@ -71,7 +49,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing command name segmentation with filter equals to the string");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_Filter = L"AAAAAABBBBBBCCC";
|
||||
auto segments = filteredCommand->_computeHighlightedName().Segments();
|
||||
VERIFY_ARE_EQUAL(segments.Size(), 1u);
|
||||
@@ -80,7 +58,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing command name segmentation with filter with first character matching");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
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);
|
||||
@@ -91,7 +69,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing command name segmentation with filter with other case");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
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);
|
||||
@@ -102,7 +80,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing command name segmentation with filter matching several characters");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
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);
|
||||
@@ -117,7 +95,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing command name segmentation with non matching filter");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
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);
|
||||
@@ -128,39 +106,17 @@ namespace TerminalAppLocalTests
|
||||
|
||||
void FilteredCommandTests::VerifyWeight()
|
||||
{
|
||||
const std::string settingsJson{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{ "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" }, "name": "AAAAAABBBBBBCCC" }
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
const auto commands = settings.GlobalSettings().Commands();
|
||||
VERIFY_ARE_EQUAL(1u, commands.Size());
|
||||
|
||||
const auto command = commands.Lookup(L"AAAAAABBBBBBCCC");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
VERIFY_ARE_EQUAL(command.Name(), L"AAAAAABBBBBBCCC");
|
||||
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
|
||||
{
|
||||
Log::Comment(L"Testing weight of command with no filter");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
||||
auto weight = filteredCommand->_computeWeight();
|
||||
VERIFY_ARE_EQUAL(weight, 0);
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing weight of command with empty filter");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_Filter = L"";
|
||||
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
||||
auto weight = filteredCommand->_computeWeight();
|
||||
@@ -168,7 +124,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing weight of command with filter equals to the string");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_Filter = L"AAAAAABBBBBBCCC";
|
||||
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
||||
auto weight = filteredCommand->_computeWeight();
|
||||
@@ -176,7 +132,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing weight of command with filter with first character matching");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_Filter = L"A";
|
||||
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
||||
auto weight = filteredCommand->_computeWeight();
|
||||
@@ -184,7 +140,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing weight of command with filter with other case");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_Filter = L"a";
|
||||
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
||||
auto weight = filteredCommand->_computeWeight();
|
||||
@@ -192,7 +148,7 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing weight of command with filter matching several characters");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_Filter = L"ab";
|
||||
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
||||
auto weight = filteredCommand->_computeWeight();
|
||||
@@ -202,50 +158,24 @@ namespace TerminalAppLocalTests
|
||||
|
||||
void FilteredCommandTests::VerifyCompare()
|
||||
{
|
||||
const std::string settingsJson{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{ "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" }, "name": "AAAAAABBBBBBCCC" },
|
||||
{ "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "horizontal" }, "name": "BBBBBCCC" }
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
const auto commands = settings.GlobalSettings().Commands();
|
||||
VERIFY_ARE_EQUAL(2u, commands.Size());
|
||||
|
||||
const auto command = commands.Lookup(L"AAAAAABBBBBBCCC");
|
||||
VERIFY_IS_NOT_NULL(command);
|
||||
VERIFY_ARE_EQUAL(command.Name(), L"AAAAAABBBBBBCCC");
|
||||
|
||||
const auto command2 = commands.Lookup(L"BBBBBCCC");
|
||||
VERIFY_IS_NOT_NULL(command2);
|
||||
VERIFY_ARE_EQUAL(command2.Name(), L"BBBBBCCC");
|
||||
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"AAAAAABBBBBBCCC") };
|
||||
const auto paletteItem2{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"BBBBBCCC") };
|
||||
{
|
||||
Log::Comment(L"Testing comparison of commands with no filter");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command2);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);
|
||||
|
||||
VERIFY_ARE_EQUAL(filteredCommand->Weight(), filteredCommand2->Weight());
|
||||
VERIFY_IS_TRUE(winrt::TerminalApp::implementation::FilteredCommand::Compare(*filteredCommand, *filteredCommand2));
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing comparison of commands with empty filter");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_Filter = L"";
|
||||
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
||||
filteredCommand->_Weight = filteredCommand->_computeWeight();
|
||||
|
||||
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command2);
|
||||
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);
|
||||
filteredCommand2->_Filter = L"";
|
||||
filteredCommand2->_HighlightedName = filteredCommand2->_computeHighlightedName();
|
||||
filteredCommand2->_Weight = filteredCommand2->_computeWeight();
|
||||
@@ -255,12 +185,12 @@ namespace TerminalAppLocalTests
|
||||
}
|
||||
{
|
||||
Log::Comment(L"Testing comparison of commands with different weights");
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
filteredCommand->_Filter = L"B";
|
||||
filteredCommand->_HighlightedName = filteredCommand->_computeHighlightedName();
|
||||
filteredCommand->_Weight = filteredCommand->_computeWeight();
|
||||
|
||||
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command2);
|
||||
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);
|
||||
filteredCommand2->_Filter = L"B";
|
||||
filteredCommand2->_HighlightedName = filteredCommand2->_computeHighlightedName();
|
||||
filteredCommand2->_Weight = filteredCommand2->_computeWeight();
|
||||
@@ -272,32 +202,11 @@ namespace TerminalAppLocalTests
|
||||
|
||||
void FilteredCommandTests::VerifyCompareIgnoreCase()
|
||||
{
|
||||
const std::string settingsJson{ R"(
|
||||
const auto paletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"a") };
|
||||
const auto paletteItem2{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(L"B") };
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{ "keys": ["ctrl+a"], "command": { "action": "splitPane", "split": "vertical" }, "name": "a" },
|
||||
{ "keys": ["ctrl+b"], "command": { "action": "splitPane", "split": "horizontal" }, "name": "B" }
|
||||
]
|
||||
})" };
|
||||
|
||||
CascadiaSettings settings{ til::u8u16(settingsJson) };
|
||||
const auto commands = settings.GlobalSettings().Commands();
|
||||
VERIFY_ARE_EQUAL(2u, commands.Size());
|
||||
|
||||
const auto command = commands.Lookup(L"a");
|
||||
const auto command2 = commands.Lookup(L"B");
|
||||
{
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command);
|
||||
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(command2);
|
||||
const auto filteredCommand = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem);
|
||||
const auto filteredCommand2 = winrt::make_self<winrt::TerminalApp::implementation::FilteredCommand>(paletteItem2);
|
||||
|
||||
VERIFY_ARE_EQUAL(filteredCommand->Weight(), filteredCommand2->Weight());
|
||||
VERIFY_IS_TRUE(winrt::TerminalApp::implementation::FilteredCommand::Compare(*filteredCommand, *filteredCommand2));
|
||||
|
||||
@@ -486,7 +486,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the first pane"));
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, nullptr);
|
||||
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, 0.5f, nullptr);
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
@@ -504,7 +504,7 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"Duplicate the pane, and don't crash"));
|
||||
result = RunOnUIThread([&page]() {
|
||||
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, nullptr);
|
||||
page->_SplitPane(SplitState::Automatic, SplitType::Duplicate, 0.5f, nullptr);
|
||||
|
||||
VERIFY_ARE_EQUAL(1u, page->_tabs.Size());
|
||||
auto tab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
|
||||
@@ -664,7 +664,7 @@ namespace TerminalAppLocalTests
|
||||
Log::Comment(L"Move focus. This will cause us to un-zoom.");
|
||||
result = RunOnUIThread([&page]() {
|
||||
// Set up action
|
||||
MoveFocusArgs args{ Direction::Left };
|
||||
MoveFocusArgs args{ FocusDirection::Left };
|
||||
ActionEventArgs eventArgs{ args };
|
||||
|
||||
page->_HandleMoveFocus(nullptr, eventArgs);
|
||||
@@ -865,14 +865,14 @@ namespace TerminalAppLocalTests
|
||||
page->_OpenNewTab(newTerminalArgs);
|
||||
page->_OpenNewTab(newTerminalArgs);
|
||||
});
|
||||
VERIFY_ARE_EQUAL(4u, page->_mruTabActions.Size());
|
||||
VERIFY_ARE_EQUAL(4u, page->_mruTabs.Size());
|
||||
|
||||
Log::Comment(L"give alphabetical names to all switch tab actions");
|
||||
RunOnUIThread([&page]() {
|
||||
page->_tabs.GetAt(0).SwitchToTabCommand().Name(L"a");
|
||||
page->_tabs.GetAt(1).SwitchToTabCommand().Name(L"b");
|
||||
page->_tabs.GetAt(2).SwitchToTabCommand().Name(L"c");
|
||||
page->_tabs.GetAt(3).SwitchToTabCommand().Name(L"d");
|
||||
page->_GetTerminalTabImpl(page->_tabs.GetAt(0))->Title(L"a");
|
||||
page->_GetTerminalTabImpl(page->_tabs.GetAt(1))->Title(L"b");
|
||||
page->_GetTerminalTabImpl(page->_tabs.GetAt(2))->Title(L"c");
|
||||
page->_GetTerminalTabImpl(page->_tabs.GetAt(3))->Title(L"d");
|
||||
});
|
||||
|
||||
Log::Comment(L"Change the tab switch order to MRU switching");
|
||||
@@ -888,11 +888,11 @@ namespace TerminalAppLocalTests
|
||||
page->_UpdatedSelectedTab(3);
|
||||
});
|
||||
|
||||
VERIFY_ARE_EQUAL(4u, page->_mruTabActions.Size());
|
||||
VERIFY_ARE_EQUAL(L"d", page->_mruTabActions.GetAt(0).Name());
|
||||
VERIFY_ARE_EQUAL(L"c", page->_mruTabActions.GetAt(1).Name());
|
||||
VERIFY_ARE_EQUAL(L"b", page->_mruTabActions.GetAt(2).Name());
|
||||
VERIFY_ARE_EQUAL(L"a", page->_mruTabActions.GetAt(3).Name());
|
||||
VERIFY_ARE_EQUAL(4u, page->_mruTabs.Size());
|
||||
VERIFY_ARE_EQUAL(L"d", page->_mruTabs.GetAt(0).Title());
|
||||
VERIFY_ARE_EQUAL(L"c", page->_mruTabs.GetAt(1).Title());
|
||||
VERIFY_ARE_EQUAL(L"b", page->_mruTabs.GetAt(2).Title());
|
||||
VERIFY_ARE_EQUAL(L"a", page->_mruTabs.GetAt(3).Title());
|
||||
|
||||
Log::Comment(L"Switch to the next MRU tab, which is the third tab");
|
||||
RunOnUIThread([&page]() {
|
||||
@@ -906,9 +906,9 @@ namespace TerminalAppLocalTests
|
||||
|
||||
Log::Comment(L"Verify command palette preserves MRU order of tabs");
|
||||
VERIFY_ARE_EQUAL(4u, palette->_filteredActions.Size());
|
||||
VERIFY_ARE_EQUAL(L"d", palette->_filteredActions.GetAt(0).Command().Name());
|
||||
VERIFY_ARE_EQUAL(L"c", palette->_filteredActions.GetAt(1).Command().Name());
|
||||
VERIFY_ARE_EQUAL(L"b", palette->_filteredActions.GetAt(2).Command().Name());
|
||||
VERIFY_ARE_EQUAL(L"a", palette->_filteredActions.GetAt(3).Command().Name());
|
||||
VERIFY_ARE_EQUAL(L"d", palette->_filteredActions.GetAt(0).Item().Name());
|
||||
VERIFY_ARE_EQUAL(L"c", palette->_filteredActions.GetAt(1).Item().Name());
|
||||
VERIFY_ARE_EQUAL(L"b", palette->_filteredActions.GetAt(2).Item().Name());
|
||||
VERIFY_ARE_EQUAL(L"a", palette->_filteredActions.GetAt(3).Item().Name());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
|
||||
<!-- If you don't reference these projects here, the
|
||||
_ConsoleGenerateAdditionalWinmdManifests step won't gather the winmd's -->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\TerminalControl.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalConnection\TerminalConnection.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)\src\cascadia\TerminalApp\dll\TerminalApp.vcxproj" />
|
||||
@@ -98,6 +99,6 @@
|
||||
|
||||
<!-- We actually can just straight up reference MUX here, it's fine -->
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -95,6 +95,8 @@
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalConnection\TerminalConnection.vcxproj">
|
||||
<Project>{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}</Project>
|
||||
</ProjectReference>
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettingsEditor\Microsoft.Terminal.Settings.Editor.vcxproj" />
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalControl\TerminalControl.vcxproj" />
|
||||
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalApp\dll\TerminalApp.vcxproj">
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN // If this is not defined, windows.h includes commdlg.h which defines FindText globally and conflicts with UIAutomation ITextRangeProvider.
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
#endif
|
||||
|
||||
#include <LibraryIncludes.h>
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMCX
|
||||
#define NOHELP
|
||||
#define NOCOMM
|
||||
|
||||
#include <LibraryIncludes.h>
|
||||
// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
|
||||
|
||||
50
src/cascadia/TerminalApp/ActionPaletteItem.cpp
Normal file
50
src/cascadia/TerminalApp/ActionPaletteItem.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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(Microsoft::Terminal::Settings::Model::Command const& command) :
|
||||
_Command(command)
|
||||
{
|
||||
Name(command.Name());
|
||||
KeyChordText(command.KeyChordText());
|
||||
Icon(command.Icon());
|
||||
|
||||
_commandChangedRevoker = command.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](auto& sender, auto& e) {
|
||||
auto item{ weakThis.get() };
|
||||
auto senderCommand{ sender.try_as<Microsoft::Terminal::Settings::Model::Command>() };
|
||||
|
||||
if (item && senderCommand)
|
||||
{
|
||||
auto changedProperty = e.PropertyName();
|
||||
if (changedProperty == L"Name")
|
||||
{
|
||||
item->Name(senderCommand.Name());
|
||||
}
|
||||
else if (changedProperty == L"KeyChordText")
|
||||
{
|
||||
item->KeyChordText(senderCommand.KeyChordText());
|
||||
}
|
||||
else if (changedProperty == L"Icon")
|
||||
{
|
||||
item->Icon(senderCommand.Icon());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
27
src/cascadia/TerminalApp/ActionPaletteItem.h
Normal file
27
src/cascadia/TerminalApp/ActionPaletteItem.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PaletteItem.h"
|
||||
#include "ActionPaletteItem.g.h"
|
||||
#include "inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct ActionPaletteItem : ActionPaletteItemT<ActionPaletteItem, PaletteItem>
|
||||
{
|
||||
ActionPaletteItem() = default;
|
||||
ActionPaletteItem(Microsoft::Terminal::Settings::Model::Command const& command);
|
||||
|
||||
GETSET_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);
|
||||
}
|
||||
14
src/cascadia/TerminalApp/ActionPaletteItem.idl
Normal file
14
src/cascadia/TerminalApp/ActionPaletteItem.idl
Normal file
@@ -0,0 +1,14 @@
|
||||
// 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);
|
||||
|
||||
Microsoft.Terminal.Settings.Model.Command Command { get; };
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,11 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
else if (const auto& realArgs = args.ActionArgs().try_as<SplitPaneArgs>())
|
||||
{
|
||||
_SplitPane(realArgs.SplitStyle(), realArgs.SplitMode(), realArgs.TerminalArgs());
|
||||
_SplitPane(realArgs.SplitStyle(),
|
||||
realArgs.SplitMode(),
|
||||
// This is safe, we're already filtering so the value is (0, 1)
|
||||
::base::saturated_cast<float>(realArgs.SplitSize()),
|
||||
realArgs.TerminalArgs());
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
@@ -130,23 +134,20 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_HandleTogglePaneZoom(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (auto focusedTab = _GetFocusedTab())
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto activeTab = _GetTerminalTabImpl(focusedTab))
|
||||
// Don't do anything if there's only one pane. It's already zoomed.
|
||||
if (activeTab->GetLeafPaneCount() > 1)
|
||||
{
|
||||
// Don't do anything if there's only one pane. It's already zoomed.
|
||||
if (activeTab && activeTab->GetLeafPaneCount() > 1)
|
||||
{
|
||||
// First thing's first, remove the current content from the UI
|
||||
// tree. This is important, because we might be leaving zoom, and if
|
||||
// a pane is zoomed, then it's currently in the UI tree, and should
|
||||
// be removed before it's re-added in Pane::Restore
|
||||
_tabContent.Children().Clear();
|
||||
// First thing's first, remove the current content from the UI
|
||||
// tree. This is important, because we might be leaving zoom, and if
|
||||
// a pane is zoomed, then it's currently in the UI tree, and should
|
||||
// be removed before it's re-added in Pane::Restore
|
||||
_tabContent.Children().Clear();
|
||||
|
||||
// Togging the zoom on the tab will cause the tab to inform us of
|
||||
// the new root Content for this tab.
|
||||
activeTab->ToggleZoom();
|
||||
}
|
||||
// Togging the zoom on the tab will cause the tab to inform us of
|
||||
// the new root Content for this tab.
|
||||
activeTab->ToggleZoom();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +168,20 @@ namespace winrt::TerminalApp::implementation
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleScrollToTop(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_ScrollToBufferEdge(ScrollUp);
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleScrollToBottom(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_ScrollToBufferEdge(ScrollDown);
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleOpenSettings(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
@@ -214,14 +229,14 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<ResizePaneArgs>())
|
||||
{
|
||||
if (realArgs.Direction() == Direction::None)
|
||||
if (realArgs.ResizeDirection() == ResizeDirection::None)
|
||||
{
|
||||
// Do nothing
|
||||
args.Handled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ResizePane(realArgs.Direction());
|
||||
_ResizePane(realArgs.ResizeDirection());
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
@@ -232,14 +247,14 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<MoveFocusArgs>())
|
||||
{
|
||||
if (realArgs.Direction() == Direction::None)
|
||||
if (realArgs.FocusDirection() == FocusDirection::None)
|
||||
{
|
||||
// Do nothing
|
||||
args.Handled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_MoveFocus(realArgs.Direction());
|
||||
_MoveFocus(realArgs.FocusDirection());
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
@@ -281,11 +296,11 @@ namespace winrt::TerminalApp::implementation
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleToggleRetroEffect(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
void TerminalPage::_HandleToggleShaderEffects(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
const auto termControl = _GetActiveControl();
|
||||
termControl.ToggleRetroEffect();
|
||||
termControl.ToggleShaderEffects();
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@@ -329,19 +344,16 @@ namespace winrt::TerminalApp::implementation
|
||||
args.Handled(false);
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SetColorSchemeArgs>())
|
||||
{
|
||||
if (auto focusedTab = _GetFocusedTab())
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto activeTab = _GetTerminalTabImpl(focusedTab))
|
||||
if (auto activeControl = activeTab->GetActiveTerminalControl())
|
||||
{
|
||||
if (auto activeControl = activeTab->GetActiveTerminalControl())
|
||||
if (const auto scheme = _settings.GlobalSettings().ColorSchemes().TryLookup(realArgs.SchemeName()))
|
||||
{
|
||||
if (const auto scheme = _settings.GlobalSettings().ColorSchemes().TryLookup(realArgs.SchemeName()))
|
||||
{
|
||||
auto controlSettings = activeControl.Settings().as<TerminalSettings>();
|
||||
controlSettings->ApplyColorScheme(scheme);
|
||||
activeControl.UpdateSettings(*controlSettings);
|
||||
args.Handled(true);
|
||||
}
|
||||
auto controlSettings = activeControl.Settings().as<TerminalSettings>();
|
||||
controlSettings->ApplyColorScheme(scheme);
|
||||
activeControl.UpdateSettings(*controlSettings);
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,18 +370,15 @@ namespace winrt::TerminalApp::implementation
|
||||
tabColor = realArgs.TabColor();
|
||||
}
|
||||
|
||||
if (auto focusedTab = _GetFocusedTab())
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto activeTab = _GetTerminalTabImpl(focusedTab))
|
||||
if (tabColor)
|
||||
{
|
||||
if (tabColor)
|
||||
{
|
||||
activeTab->SetRuntimeTabColor(tabColor.Value());
|
||||
}
|
||||
else
|
||||
{
|
||||
activeTab->ResetRuntimeTabColor();
|
||||
}
|
||||
activeTab->SetRuntimeTabColor(tabColor.Value());
|
||||
}
|
||||
else
|
||||
{
|
||||
activeTab->ResetRuntimeTabColor();
|
||||
}
|
||||
}
|
||||
args.Handled(true);
|
||||
@@ -378,12 +387,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_HandleOpenTabColorPicker(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (auto focusedTab = _GetFocusedTab())
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto activeTab = _GetTerminalTabImpl(focusedTab))
|
||||
{
|
||||
activeTab->ActivateColorPicker();
|
||||
}
|
||||
activeTab->ActivateColorPicker();
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
@@ -398,18 +404,15 @@ namespace winrt::TerminalApp::implementation
|
||||
title = realArgs.Title();
|
||||
}
|
||||
|
||||
if (auto focusedTab = _GetFocusedTab())
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto activeTab = _GetTerminalTabImpl(focusedTab))
|
||||
if (title.has_value())
|
||||
{
|
||||
if (title.has_value())
|
||||
{
|
||||
activeTab->SetTabText(title.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
activeTab->ResetTabText();
|
||||
}
|
||||
activeTab->SetTabText(title.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
activeTab->ResetTabText();
|
||||
}
|
||||
}
|
||||
args.Handled(true);
|
||||
@@ -418,12 +421,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_HandleOpenTabRenamer(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (auto focusedTab = _GetFocusedTab())
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto activeTab = _GetTerminalTabImpl(focusedTab))
|
||||
{
|
||||
activeTab->ActivateTabRenamer();
|
||||
}
|
||||
activeTab->ActivateTabRenamer();
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
@@ -522,7 +522,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
// Tab search is always in-order.
|
||||
_UpdatePaletteWithInOrderTabs();
|
||||
CommandPalette().SetTabs(_tabs, true);
|
||||
|
||||
auto opt = _GetFocusedTabIndex();
|
||||
uint32_t startIdx = opt.value_or(0);
|
||||
|
||||
@@ -247,6 +247,10 @@ void AppCommandlineArgs::_buildSplitPaneParser()
|
||||
_splitVertical,
|
||||
RS_A(L"CmdSplitPaneVerticalArgDesc"));
|
||||
subcommand._verticalOption->excludes(subcommand._horizontalOption);
|
||||
auto* sizeOpt = subcommand.subcommand->add_option("-s,--size",
|
||||
_splitPaneSize,
|
||||
RS_A(L"CmdSplitPaneSizeArgDesc"));
|
||||
sizeOpt->check(CLI::Range(0.01f, 0.99f));
|
||||
|
||||
// When ParseCommand is called, if this subcommand was provided, this
|
||||
// callback function will be triggered on the same thread. We can be sure
|
||||
@@ -274,7 +278,7 @@ void AppCommandlineArgs::_buildSplitPaneParser()
|
||||
style = SplitState::Vertical;
|
||||
}
|
||||
}
|
||||
SplitPaneArgs args{ style, terminalArgs };
|
||||
SplitPaneArgs args{ style, _splitPaneSize, terminalArgs };
|
||||
splitPaneActionAndArgs.Args(args);
|
||||
_startupActions.push_back(splitPaneActionAndArgs);
|
||||
});
|
||||
@@ -720,3 +724,75 @@ int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring>& args)
|
||||
// built in _appArgs, which we'll use when the application starts up.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Attempts to parse an array of commandline args into a list of
|
||||
// commands to execute, and then parses these commands. As commands are
|
||||
// successfully parsed, they will generate ShortcutActions for us to be
|
||||
// able to execute. If we fail to parse any commands, we'll return the
|
||||
// error code from the failure to parse that command, and stop processing
|
||||
// additional commands.
|
||||
// - The first arg in args should be the program name "wt" (or some variant). It
|
||||
// will be ignored during parsing.
|
||||
// Arguments:
|
||||
// - args: ExecuteCommandlineArgs describing the command line to parse
|
||||
// Return Value:
|
||||
// - 0 if the commandline was successfully parsed
|
||||
int AppCommandlineArgs::ParseArgs(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args)
|
||||
{
|
||||
if (!args || args.Commandline().empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert the commandline into an array of args with
|
||||
// CommandLineToArgvW, similar to how the app typically does when
|
||||
// called from the commandline.
|
||||
int argc = 0;
|
||||
wil::unique_any<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(args.Commandline().c_str(), &argc) };
|
||||
if (argv)
|
||||
{
|
||||
std::vector<winrt::hstring> args;
|
||||
|
||||
// Make sure the first argument is wt.exe, because ParseArgs will
|
||||
// always skip the program name. The particular value of this first
|
||||
// string doesn't terribly matter.
|
||||
args.emplace_back(L"wt.exe");
|
||||
for (auto& elem : wil::make_range(argv.get(), argc))
|
||||
{
|
||||
args.emplace_back(elem);
|
||||
}
|
||||
winrt::array_view<const winrt::hstring> argsView{ args };
|
||||
return ParseArgs(argsView);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Allows disabling addition of help-related info in the exit message
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AppCommandlineArgs::DisableHelpInExitMessage()
|
||||
{
|
||||
_app.set_help_flag();
|
||||
_app.set_help_all_flag();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Resets the state to allow external consumers to reuse this instance
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void AppCommandlineArgs::FullResetState()
|
||||
{
|
||||
_resetStateToDefault();
|
||||
|
||||
_currentCommandline = nullptr;
|
||||
_launchMode = std::nullopt;
|
||||
_startupActions.clear();
|
||||
_exitMessage = "";
|
||||
_shouldExitEarly = false;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@ public:
|
||||
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> GetLaunchMode() const noexcept;
|
||||
|
||||
int ParseArgs(const winrt::Microsoft::Terminal::Settings::Model::ExecuteCommandlineArgs& args);
|
||||
void DisableHelpInExitMessage();
|
||||
void FullResetState();
|
||||
|
||||
private:
|
||||
static const std::wregex _commandDelimiterRegex;
|
||||
|
||||
@@ -80,21 +84,21 @@ private:
|
||||
// _commandline will contain the command line with which we'll be spawning a new terminal
|
||||
std::vector<std::string> _commandline;
|
||||
|
||||
const Commandline* _currentCommandline{ nullptr };
|
||||
|
||||
bool _splitVertical{ false };
|
||||
bool _splitHorizontal{ false };
|
||||
float _splitPaneSize{ 0.5f };
|
||||
|
||||
int _focusTabIndex{ -1 };
|
||||
bool _focusNextTab{ false };
|
||||
bool _focusPrevTab{ false };
|
||||
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
|
||||
// Are you adding more args here? Make sure to reset them in _resetStateToDefault
|
||||
|
||||
const Commandline* _currentCommandline{ nullptr };
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::LaunchMode> _launchMode{ std::nullopt };
|
||||
std::vector<winrt::Microsoft::Terminal::Settings::Model::ActionAndArgs> _startupActions;
|
||||
std::string _exitMessage;
|
||||
bool _shouldExitEarly{ false };
|
||||
// Are you adding more args or attributes here? If they are not reset in _resetStateToDefault, make sure to reset them in FullResetState
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs _getNewTerminalArgs(NewTerminalSubcommand& subcommand);
|
||||
void _addNewTerminalArgs(NewTerminalSubcommand& subcommand);
|
||||
|
||||
@@ -42,7 +42,8 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWar
|
||||
USES_RESOURCE(L"LegacyGlobalsProperty"),
|
||||
USES_RESOURCE(L"FailedToParseCommandJson"),
|
||||
USES_RESOURCE(L"FailedToWriteToSettings"),
|
||||
USES_RESOURCE(L"InvalidColorSchemeInCmd")
|
||||
USES_RESOURCE(L"InvalidColorSchemeInCmd"),
|
||||
USES_RESOURCE(L"InvalidSplitSize")
|
||||
};
|
||||
static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadErrors::ERRORS_SIZE)> settingsLoadErrorsLabels {
|
||||
USES_RESOURCE(L"NoProfilesText"),
|
||||
@@ -591,10 +592,10 @@ namespace winrt::TerminalApp::implementation
|
||||
auto tabControl = TabRowControl();
|
||||
tabControl.Measure({ SHRT_MAX, SHRT_MAX });
|
||||
|
||||
// For whatever reason, there's about 6px of unaccounted-for space
|
||||
// in the application. I couldn't tell you where these 6px are
|
||||
// For whatever reason, there's about 10px of unaccounted-for space
|
||||
// in the application. I couldn't tell you where these 10px are
|
||||
// coming from, but they need to be included in this math.
|
||||
proposedSize.Width += (tabControl.DesiredSize().Height + 6) * scale;
|
||||
proposedSize.Height += (tabControl.DesiredSize().Height + 10) * scale;
|
||||
}
|
||||
|
||||
return proposedSize;
|
||||
|
||||
26
src/cascadia/TerminalApp/CommandLinePaletteItem.cpp
Normal file
26
src/cascadia/TerminalApp/CommandLinePaletteItem.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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(winrt::hstring const& commandLine) :
|
||||
_CommandLine(commandLine)
|
||||
{
|
||||
Name(commandLine);
|
||||
}
|
||||
}
|
||||
24
src/cascadia/TerminalApp/CommandLinePaletteItem.h
Normal file
24
src/cascadia/TerminalApp/CommandLinePaletteItem.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PaletteItem.h"
|
||||
#include "CommandLinePaletteItem.g.h"
|
||||
#include "inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct CommandLinePaletteItem : CommandLinePaletteItemT<CommandLinePaletteItem, PaletteItem>
|
||||
{
|
||||
CommandLinePaletteItem() = default;
|
||||
CommandLinePaletteItem(winrt::hstring const& commandLine);
|
||||
|
||||
GETSET_PROPERTY(winrt::hstring, CommandLine);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(CommandLinePaletteItem);
|
||||
}
|
||||
12
src/cascadia/TerminalApp/CommandLinePaletteItem.idl
Normal file
12
src/cascadia/TerminalApp/CommandLinePaletteItem.idl
Normal file
@@ -0,0 +1,12 @@
|
||||
import "PaletteItem.idl";
|
||||
import "TabBase.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass CommandLinePaletteItem : PaletteItem
|
||||
{
|
||||
CommandLinePaletteItem(String commandLine);
|
||||
|
||||
String CommandLine { get; };
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,10 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "ActionPaletteItem.h"
|
||||
#include "TabPaletteItem.h"
|
||||
#include "CommandLinePaletteItem.h"
|
||||
#include "CommandPalette.h"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
|
||||
#include "CommandPalette.g.cpp"
|
||||
@@ -96,6 +98,8 @@ namespace winrt::TerminalApp::implementation
|
||||
});
|
||||
|
||||
_filteredActionsView().SelectionChanged({ this, &CommandPalette::_selectedCommandChanged });
|
||||
|
||||
_appArgs.DisableHelpInExitMessage();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -224,11 +228,8 @@ namespace winrt::TerminalApp::implementation
|
||||
if (_currentMode == CommandPaletteMode::TabSwitchMode)
|
||||
{
|
||||
const auto selectedCommand = _filteredActionsView().SelectedItem();
|
||||
if (const auto filteredCommand = selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>())
|
||||
{
|
||||
const auto& actionAndArgs = filteredCommand.Command().Action();
|
||||
_dispatch.DoAction(actionAndArgs);
|
||||
}
|
||||
const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>() };
|
||||
_switchToTab(filteredCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +291,6 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
||||
{
|
||||
auto key = e.OriginalKey();
|
||||
auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
|
||||
|
||||
if (key == VirtualKey::Up)
|
||||
{
|
||||
@@ -438,6 +438,44 @@ namespace winrt::TerminalApp::implementation
|
||||
void CommandPalette::_rootPointerPressed(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Windows::UI::Xaml::Input::PointerRoutedEventArgs const& /*e*/)
|
||||
{
|
||||
if (Visibility() != Visibility::Collapsed)
|
||||
{
|
||||
_dismissPalette();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - The purpose of this event handler is to hide the palette if it loses focus.
|
||||
// We say we lost focus if our root element and all its descendants lost focus.
|
||||
// This handler is invoked when our root element or some descendant loses focus.
|
||||
// At this point we need to learn if the newly focused element belongs to this palette.
|
||||
// To achieve this:
|
||||
// - We start with the newly focused element and traverse its visual ancestors up to the Xaml root.
|
||||
// - If one of the ancestors is this CommandPalette, then by our definition the focus is not lost
|
||||
// - If we reach the Xaml root without meeting this CommandPalette,
|
||||
// then the focus is not contained in it anymore and it should be dismissed
|
||||
// Arguments:
|
||||
// - <unused>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CommandPalette::_lostFocusHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Windows::UI::Xaml::RoutedEventArgs const& /*args*/)
|
||||
{
|
||||
auto focusedElementOrAncestor = Input::FocusManager::GetFocusedElement(this->XamlRoot()).try_as<DependencyObject>();
|
||||
while (focusedElementOrAncestor)
|
||||
{
|
||||
if (focusedElementOrAncestor == *this)
|
||||
{
|
||||
// This palette is the focused element or an ancestor of the focused element. No need to dismiss.
|
||||
return;
|
||||
}
|
||||
|
||||
// Go up to the next ancestor
|
||||
focusedElementOrAncestor = winrt::Windows::UI::Xaml::Media::VisualTreeHelper::GetParent(focusedElementOrAncestor);
|
||||
}
|
||||
|
||||
// We got to the root (the element with no parent) and didn't meet this palette on the path.
|
||||
// It means that it lost the focus and needs to be dismissed.
|
||||
_dismissPalette();
|
||||
}
|
||||
|
||||
@@ -562,48 +600,56 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_dispatchCommandline(filteredCommand);
|
||||
}
|
||||
else if (_currentMode == CommandPaletteMode::TabSwitchMode || _currentMode == CommandPaletteMode::TabSearchMode)
|
||||
{
|
||||
_switchToTab(filteredCommand);
|
||||
_close();
|
||||
}
|
||||
else if (filteredCommand)
|
||||
{
|
||||
if (filteredCommand.Command().HasNestedCommands())
|
||||
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
|
||||
{
|
||||
// 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(filteredCommand.Command().Name());
|
||||
_currentNestedCommands.Clear();
|
||||
for (const auto& nameAndCommand : filteredCommand.Command().NestedCommands())
|
||||
if (actionPaletteItem.Command().HasNestedCommands())
|
||||
{
|
||||
const auto action = nameAndCommand.Value();
|
||||
auto nestedFilteredCommand{ winrt::make<FilteredCommand>(action) };
|
||||
_currentNestedCommands.Append(nestedFilteredCommand);
|
||||
// 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());
|
||||
_currentNestedCommands.Clear();
|
||||
for (const auto& nameAndCommand : actionPaletteItem.Command().NestedCommands())
|
||||
{
|
||||
const auto action = nameAndCommand.Value();
|
||||
auto nestedActionPaletteItem{ winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(action) };
|
||||
auto nestedFilteredCommand{ winrt::make<FilteredCommand>(nestedActionPaletteItem) };
|
||||
_currentNestedCommands.Append(nestedFilteredCommand);
|
||||
}
|
||||
|
||||
_updateUIForStackChange();
|
||||
}
|
||||
else
|
||||
{
|
||||
// First stash the search text length, because _close will clear this.
|
||||
const auto searchTextLength = _searchBox().Text().size();
|
||||
|
||||
_updateUIForStackChange();
|
||||
}
|
||||
else
|
||||
{
|
||||
// First stash the search text length, because _close will clear this.
|
||||
const auto searchTextLength = _searchBox().Text().size();
|
||||
// An action from the root command list has depth=0
|
||||
const auto nestedCommandDepth = _nestedActionStack.Size();
|
||||
|
||||
// An action from the root command list has depth=0
|
||||
const auto nestedCommandDepth = _nestedActionStack.Size();
|
||||
// Close before we dispatch so that actions that open the command
|
||||
// palette like the Tab Switcher will be able to have the last laugh.
|
||||
_close();
|
||||
|
||||
// Close before we dispatch so that actions that open the command
|
||||
// palette like the Tab Switcher will be able to have the last laugh.
|
||||
_close();
|
||||
_DispatchCommandRequestedHandlers(*this, actionPaletteItem.Command());
|
||||
|
||||
const auto actionAndArgs = filteredCommand.Command().Action();
|
||||
_dispatch.DoAction(actionAndArgs);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
|
||||
"CommandPaletteDispatchedAction",
|
||||
TraceLoggingDescription("Event emitted when the user selects an action in the Command Palette"),
|
||||
TraceLoggingUInt32(searchTextLength, "SearchTextLength", "Number of characters in the search string"),
|
||||
TraceLoggingUInt32(nestedCommandDepth, "NestedCommandDepth", "the depth in the tree of commands for the dispatched action"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
|
||||
"CommandPaletteDispatchedAction",
|
||||
TraceLoggingDescription("Event emitted when the user selects an action in the Command Palette"),
|
||||
TraceLoggingUInt32(searchTextLength, "SearchTextLength", "Number of characters in the search string"),
|
||||
TraceLoggingUInt32(nestedCommandDepth, "NestedCommandDepth", "the depth in the tree of commands for the dispatched action"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -632,6 +678,26 @@ namespace winrt::TerminalApp::implementation
|
||||
return input.substr(firstNonSpace);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Dispatch switch to tab action.
|
||||
// Arguments:
|
||||
// - filteredCommand - Selected filtered command - might be null
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CommandPalette::_switchToTab(winrt::TerminalApp::FilteredCommand const& filteredCommand)
|
||||
{
|
||||
if (filteredCommand)
|
||||
{
|
||||
if (const auto tabPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::TabPaletteItem>() })
|
||||
{
|
||||
if (const auto tab{ tabPaletteItem.Tab() })
|
||||
{
|
||||
_SwitchToTabRequestedHandlers(*this, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Dispatch the current search text as a ExecuteCommandline action.
|
||||
// Arguments:
|
||||
@@ -656,8 +722,9 @@ namespace winrt::TerminalApp::implementation
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
if (_dispatch.DoAction(filteredCommand.value().Command().Action()))
|
||||
if (const auto commandLinePaletteItem{ filteredCommand.value().Item().try_as<winrt::TerminalApp::CommandLinePaletteItem>() })
|
||||
{
|
||||
_CommandLineExecutionRequestedHandlers(*this, commandLinePaletteItem.CommandLine());
|
||||
_close();
|
||||
}
|
||||
}
|
||||
@@ -670,13 +737,9 @@ namespace winrt::TerminalApp::implementation
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Build the ExecuteCommandline action from the values we've parsed on the commandline.
|
||||
ExecuteCommandlineArgs args{ commandLine };
|
||||
ActionAndArgs executeActionAndArgs{ ShortcutAction::ExecuteCommandline, args };
|
||||
Command command{};
|
||||
command.Action(executeActionAndArgs);
|
||||
command.Name(commandLine);
|
||||
return winrt::make<FilteredCommand>(command);
|
||||
winrt::hstring cl{ commandLine };
|
||||
auto commandLinePaletteItem{ winrt::make<winrt::TerminalApp::implementation::CommandLinePaletteItem>(cl) };
|
||||
return winrt::make<FilteredCommand>(commandLinePaletteItem);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -733,6 +796,35 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_noMatchesText().Visibility(Visibility::Collapsed);
|
||||
}
|
||||
|
||||
if (_currentMode == CommandPaletteMode::CommandlineMode)
|
||||
{
|
||||
ParsedCommandLineText(L"");
|
||||
|
||||
const auto commandLine = _getTrimmedInput();
|
||||
if (!commandLine.empty())
|
||||
{
|
||||
ExecuteCommandlineArgs args{ commandLine };
|
||||
_appArgs.FullResetState();
|
||||
if (_appArgs.ParseArgs(args) == 0)
|
||||
{
|
||||
const auto& commands = _appArgs.GetStartupActions();
|
||||
if (commands.size() > 0)
|
||||
{
|
||||
std::wstring commandDescription{ RS_(L"CommandPalette_ParsedCommandLine") };
|
||||
for (const auto& command : commands)
|
||||
{
|
||||
commandDescription += L"\n\t" + command.Args().GenerateName();
|
||||
}
|
||||
ParsedCommandLineText(commandDescription.data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ParsedCommandLineText(RS_(L"CommandPalette_FailedParsingCommandLine") + L"\n\t" + til::u8u16(_appArgs.GetExitMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPalette::_evaluatePrefix()
|
||||
@@ -770,13 +862,27 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void CommandPalette::SetCommands(Collections::IVector<Command> const& actions)
|
||||
{
|
||||
_populateFilteredActions(_allCommands, actions);
|
||||
_allCommands.Clear();
|
||||
for (const auto& action : actions)
|
||||
{
|
||||
auto actionPaletteItem{ winrt::make<winrt::TerminalApp::implementation::ActionPaletteItem>(action) };
|
||||
auto filteredCommand{ winrt::make<FilteredCommand>(actionPaletteItem) };
|
||||
_allCommands.Append(filteredCommand);
|
||||
}
|
||||
|
||||
_updateFilteredActions();
|
||||
}
|
||||
|
||||
void CommandPalette::SetTabActions(Collections::IVector<Command> const& tabs, const bool clearList)
|
||||
void CommandPalette::SetTabs(Collections::IVector<TabBase> const& tabs, const bool clearList)
|
||||
{
|
||||
_populateFilteredActions(_tabActions, tabs);
|
||||
_tabActions.Clear();
|
||||
for (const auto& tab : tabs)
|
||||
{
|
||||
auto tabPaletteItem{ winrt::make<winrt::TerminalApp::implementation::TabPaletteItem>(tab) };
|
||||
auto filteredCommand{ winrt::make<FilteredCommand>(tabPaletteItem) };
|
||||
_tabActions.Append(filteredCommand);
|
||||
}
|
||||
|
||||
// The smooth remove/add animations that happen during
|
||||
// UpdateFilteredActions don't work very well with changing the tab
|
||||
// order, because of the sheer amount of remove/adds. So, let's just
|
||||
@@ -791,24 +897,6 @@ namespace winrt::TerminalApp::implementation
|
||||
_updateFilteredActions();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This helper function is responsible to update a collection of filtered commands (e.g., tab switcher commands)
|
||||
// with the new values
|
||||
// Arguments:
|
||||
// - vectorToPopulate - the vector of filtered commands to populate
|
||||
// - actions - the raw commands to use
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CommandPalette::_populateFilteredActions(Collections::IVector<winrt::TerminalApp::FilteredCommand> const& vectorToPopulate, Collections::IVector<Command> const& actions)
|
||||
{
|
||||
vectorToPopulate.Clear();
|
||||
for (const auto& action : actions)
|
||||
{
|
||||
auto filteredCommand{ winrt::make<FilteredCommand>(action) };
|
||||
vectorToPopulate.Append(filteredCommand);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPalette::EnableCommandPaletteMode(CommandPaletteLaunchMode const launchMode)
|
||||
{
|
||||
const auto mode = (launchMode == CommandPaletteLaunchMode::CommandLine) ?
|
||||
@@ -837,6 +925,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
ParsedCommandLineText(L"");
|
||||
_searchBox().Text(L"");
|
||||
_searchBox().Select(_searchBox().Text().size(), 0);
|
||||
// Leaving this block of code outside the above if-statement
|
||||
@@ -924,7 +1013,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
for (uint32_t j = i; j < _filteredActions.Size(); j++)
|
||||
{
|
||||
if (_filteredActions.GetAt(j).Command() == actions[i].Command())
|
||||
if (_filteredActions.GetAt(j).Item() == actions[i].Item())
|
||||
{
|
||||
for (uint32_t k = i; k < j; k++)
|
||||
{
|
||||
@@ -934,7 +1023,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
if (_filteredActions.GetAt(i).Command() != actions[i].Command())
|
||||
if (_filteredActions.GetAt(i).Item() != actions[i].Item())
|
||||
{
|
||||
_filteredActions.InsertAt(i, actions[i]);
|
||||
}
|
||||
@@ -953,11 +1042,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPalette::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch)
|
||||
{
|
||||
_dispatch = dispatch;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Dismiss the command palette. This will:
|
||||
// * select all the current text in the input box
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "FilteredCommand.h"
|
||||
#include "CommandPalette.g.h"
|
||||
#include "AppCommandlineArgs.h"
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
// fwdecl unittest classes
|
||||
@@ -30,13 +31,11 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> FilteredActions();
|
||||
|
||||
void SetCommands(Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command> const& actions);
|
||||
void SetTabActions(Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command> const& tabs, const bool clearList);
|
||||
void SetTabs(Windows::Foundation::Collections::IVector<winrt::TerminalApp::TabBase> const& tabs, const bool clearList);
|
||||
void SetKeyBindings(Microsoft::Terminal::TerminalControl::IKeyBindings bindings);
|
||||
|
||||
void EnableCommandPaletteMode(Microsoft::Terminal::Settings::Model::CommandPaletteLaunchMode const launchMode);
|
||||
|
||||
void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch);
|
||||
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
|
||||
|
||||
void SelectNextItem(const bool moveDown);
|
||||
@@ -56,6 +55,11 @@ namespace winrt::TerminalApp::implementation
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, PrefixCharacter, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, ControlName, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, ParentCommandName, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, ParsedCommandLineText, _PropertyChangedHandlers);
|
||||
|
||||
TYPED_EVENT(SwitchToTabRequested, winrt::TerminalApp::CommandPalette, winrt::TerminalApp::TabBase);
|
||||
TYPED_EVENT(CommandLineExecutionRequested, winrt::TerminalApp::CommandPalette, winrt::hstring);
|
||||
TYPED_EVENT(DispatchCommandRequested, winrt::TerminalApp::CommandPalette, Microsoft::Terminal::Settings::Model::Command);
|
||||
|
||||
private:
|
||||
friend struct CommandPaletteT<CommandPalette>; // for Xaml to bind events
|
||||
@@ -65,7 +69,6 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::FilteredCommand> _filteredActions{ nullptr };
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _nestedActionStack{ nullptr };
|
||||
|
||||
winrt::TerminalApp::ShortcutActionDispatch _dispatch;
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandsToFilter();
|
||||
|
||||
bool _lastFilterTextWasEmpty{ true };
|
||||
@@ -85,6 +88,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void _updateUIForStackChange();
|
||||
|
||||
void _rootPointerPressed(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
|
||||
void _lostFocusHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
|
||||
|
||||
void _backdropPointerPressed(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
|
||||
|
||||
void _listItemClicked(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::ItemClickEventArgs const& e);
|
||||
@@ -93,12 +99,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _updateFilteredActions();
|
||||
|
||||
void _populateFilteredActions(Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> const& vectorToPopulate,
|
||||
Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command> const& actions);
|
||||
|
||||
std::vector<winrt::TerminalApp::FilteredCommand> _collectFilteredActions();
|
||||
|
||||
static int _getWeight(const winrt::hstring& searchText, const winrt::hstring& name);
|
||||
void _close();
|
||||
|
||||
CommandPaletteMode _currentMode;
|
||||
@@ -118,6 +120,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _dispatchCommand(winrt::TerminalApp::FilteredCommand const& command);
|
||||
void _dispatchCommandline(winrt::TerminalApp::FilteredCommand const& command);
|
||||
void _switchToTab(winrt::TerminalApp::FilteredCommand const& command);
|
||||
std::optional<winrt::TerminalApp::FilteredCommand> _buildCommandLineCommand(std::wstring const& commandLine);
|
||||
|
||||
void _dismissPalette();
|
||||
@@ -127,6 +130,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
static constexpr int CommandLineHistoryLength = 10;
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandLineHistory{ nullptr };
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
|
||||
friend class TerminalAppLocalTests::TabTests;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "TabBase.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
import "ShortcutActionDispatch.idl";
|
||||
import "HighlightedTextControl.idl";
|
||||
import "FilteredCommand.idl";
|
||||
|
||||
@@ -17,18 +17,21 @@ namespace TerminalApp
|
||||
String PrefixCharacter { get; };
|
||||
String ControlName { get; };
|
||||
String ParentCommandName { get; };
|
||||
String ParsedCommandLineText { get; };
|
||||
|
||||
Windows.Foundation.Collections.IObservableVector<FilteredCommand> FilteredActions { get; };
|
||||
|
||||
void SetCommands(Windows.Foundation.Collections.IVector<Microsoft.Terminal.Settings.Model.Command> actions);
|
||||
void SetTabActions(Windows.Foundation.Collections.IVector<Microsoft.Terminal.Settings.Model.Command> tabs, Boolean clearList);
|
||||
void SetTabs(Windows.Foundation.Collections.IVector<TabBase> tabs, Boolean clearList);
|
||||
void SetKeyBindings(Microsoft.Terminal.TerminalControl.IKeyBindings bindings);
|
||||
void EnableCommandPaletteMode(Microsoft.Terminal.Settings.Model.CommandPaletteLaunchMode launchMode);
|
||||
|
||||
void SelectNextItem(Boolean moveDown);
|
||||
|
||||
void SetDispatch(ShortcutActionDispatch dispatch);
|
||||
|
||||
void EnableTabSwitcherMode(Boolean searchMode, UInt32 startIdx);
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<CommandPalette, TabBase> SwitchToTabRequested;
|
||||
event Windows.Foundation.TypedEventHandler<CommandPalette, Microsoft.Terminal.Settings.Model.Command> DispatchCommandRequested;
|
||||
event Windows.Foundation.TypedEventHandler<CommandPalette, String> CommandLineExecutionRequested;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:model="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@@ -17,6 +18,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
PreviewKeyDown="_previewKeyDownHandler"
|
||||
KeyDown="_keyDownHandler"
|
||||
PreviewKeyUp="_keyUpHandler"
|
||||
LostFocus="_lostFocusHandler"
|
||||
mc:Ignorable="d"
|
||||
AutomationProperties.Name="{x:Bind ControlName, Mode=OneWay}">
|
||||
|
||||
@@ -29,9 +31,10 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
|
||||
<!-- This creates an instance of our CommandKeyChordVisibilityConverter we can reference below -->
|
||||
<local:EmptyStringVisibilityConverter x:Key="CommandKeyChordVisibilityConverter"/>
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParsedCommandLineTextVisibilityConverter"/>
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParentCommandVisibilityConverter"/>
|
||||
<local:HasNestedCommandsVisibilityConverter x:Key="HasNestedCommandsVisibilityConverter"/>
|
||||
<local:IconPathConverter x:Key="IconSourceConverter"/>
|
||||
<model:IconPathConverter x:Key="IconSourceConverter"/>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
@@ -67,6 +70,16 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
|
||||
<!-- ParsedCommandLineText styles -->
|
||||
<Style x:Key="ParsedCommandLineBorderStyle" TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="1" />
|
||||
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
<Style x:Key="ParsedCommandLineTextBlockStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Style x:Key="CommandPaletteBackground" TargetType="Grid">
|
||||
@@ -98,6 +111,16 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
|
||||
<!-- ParsedCommandLineText styles -->
|
||||
<Style x:Key="ParsedCommandLineBorderStyle" TargetType="Border">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="1" />
|
||||
<Setter Property="Background" Value="{ThemeResource SystemAltMediumLowColor}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
<Style x:Key="ParsedCommandLineTextBlockStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseMediumBrush}" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<Style x:Key="CommandPaletteBackground" TargetType="Grid">
|
||||
@@ -108,6 +131,9 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<Style x:Key="KeyChordBorderStyle" TargetType="Border"/>
|
||||
<Style x:Key="KeyChordTextBlockStyle" TargetType="TextBlock"/>
|
||||
|
||||
<!-- ParsedCommandLineText styles (use XAML defaults for High Contrast theme) -->
|
||||
<Style x:Key="ParsedCommandLineBoderStyle" TargetType="Border"/>
|
||||
<Style x:Key="ParsedCommandLineTextBlockStyle" TargetType="TextBlock"/>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
@@ -226,6 +252,22 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
Text="{x:Bind NoMatchesText, Mode=OneWay}">
|
||||
</TextBlock>
|
||||
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Visibility="{x:Bind ParsedCommandLineText, Mode=OneWay, Converter={StaticResource ParsedCommandLineTextVisibilityConverter}}"
|
||||
Style="{ThemeResource ParsedCommandLineBorderStyle}"
|
||||
Padding="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center">
|
||||
|
||||
<ScrollViewer MaxHeight="200" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock
|
||||
FontStyle="Italic"
|
||||
TextWrapping="Wrap"
|
||||
Text="{x:Bind ParsedCommandLineText, Mode=OneWay}"/>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
|
||||
<ListView
|
||||
Grid.Row="2"
|
||||
x:Name="_filteredActionsView"
|
||||
@@ -245,8 +287,9 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<!-- This HorizontalContentAlignment="Stretch" is important
|
||||
to make sure it takes the entire width of the line -->
|
||||
<ListViewItem HorizontalContentAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Command.Name, Mode=OneWay}"
|
||||
AutomationProperties.AcceleratorKey="{x:Bind Command.KeyChordText, Mode=OneWay}">
|
||||
IsTabStop="False"
|
||||
AutomationProperties.Name="{x:Bind Item.Name, Mode=OneWay}"
|
||||
AutomationProperties.AcceleratorKey="{x:Bind Item.KeyChordText, Mode=OneWay}">
|
||||
|
||||
<Grid HorizontalAlignment="Stretch" ColumnSpacing="8" >
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -260,7 +303,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind Command.Icon,
|
||||
IconSource="{x:Bind Item.Icon,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource IconSourceConverter}}"/>
|
||||
|
||||
@@ -274,7 +317,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
CommandKeyChordVisibilityConverter for details. -->
|
||||
<Border
|
||||
Grid.Column="2"
|
||||
Visibility="{x:Bind Command.KeyChordText,
|
||||
Visibility="{x:Bind Item.KeyChordText,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource CommandKeyChordVisibilityConverter}}"
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
@@ -285,7 +328,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<TextBlock
|
||||
Style="{ThemeResource KeyChordTextBlockStyle}"
|
||||
FontSize="12"
|
||||
Text="{x:Bind Command.KeyChordText, Mode=OneWay}" />
|
||||
Text="{x:Bind Item.KeyChordText, Mode=OneWay}" />
|
||||
</Border>
|
||||
|
||||
<!-- xE70E is ChevronUp. Rotated 90 degrees, it's _ChevronRight_ -->
|
||||
@@ -293,7 +336,7 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
HorizontalAlignment="Right"
|
||||
Visibility="{x:Bind Command.HasNestedCommands,
|
||||
Visibility="{x:Bind Item,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource HasNestedCommandsVisibilityConverter}}"
|
||||
Grid.Column="2">
|
||||
|
||||
@@ -19,17 +19,17 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// This is a view model class that extends the Command model,
|
||||
// by managing a highlighted text that is computed by matching search filter characters to command name
|
||||
FilteredCommand::FilteredCommand(Microsoft::Terminal::Settings::Model::Command const& command) :
|
||||
_Command(command),
|
||||
// This class is a wrapper of PaletteItem, 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(winrt::TerminalApp::PaletteItem const& item) :
|
||||
_Item(item),
|
||||
_Filter(L""),
|
||||
_Weight(0)
|
||||
{
|
||||
_HighlightedName = _computeHighlightedName();
|
||||
|
||||
// Recompute the highlighted name if the command name changes
|
||||
_commandChangedRevoker = _Command.PropertyChanged(winrt::auto_revoke, [weakThis{ get_weak() }](Windows::Foundation::IInspectable const& /*sender*/, Data::PropertyChangedEventArgs const& e) {
|
||||
// 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")
|
||||
{
|
||||
@@ -52,13 +52,13 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Looks up the filter characters within the command name.
|
||||
// Iterating through the filter and the command name it tries to associate the next filter character
|
||||
// with the first appearance of this character in the command name suffix.
|
||||
// - 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 command name is then split into segments (groupings of matched and non matched characters).
|
||||
// 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".
|
||||
//
|
||||
@@ -73,7 +73,7 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::TerminalApp::HighlightedText FilteredCommand::_computeHighlightedName()
|
||||
{
|
||||
const auto segments = winrt::single_threaded_observable_vector<winrt::TerminalApp::HighlightedTextSegment>();
|
||||
auto commandName = _Command.Name();
|
||||
auto commandName = _Item.Name();
|
||||
bool isProcessingMatchedSegment = false;
|
||||
uint32_t nextOffsetToReport = 0;
|
||||
uint32_t currentOffset = 0;
|
||||
@@ -86,7 +86,7 @@ namespace winrt::TerminalApp::implementation
|
||||
if (currentOffset == commandName.size())
|
||||
{
|
||||
// There are still unmatched filter characters but we finished scanning the name.
|
||||
// In this case we return the entire command name as unmatched
|
||||
// In this case we return the entire item name as unmatched
|
||||
auto entireNameSegment{ winrt::make<HighlightedTextSegment>(commandName, false) };
|
||||
segments.Clear();
|
||||
segments.Append(entireNameSegment);
|
||||
@@ -120,7 +120,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Either the filter or the command name were fully processed.
|
||||
// Either the filter or the item name were fully processed.
|
||||
// If we were in the middle of the matched segment - add it.
|
||||
if (isProcessingMatchedSegment)
|
||||
{
|
||||
@@ -135,7 +135,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Now create a segment for all remaining characters.
|
||||
// We will have remaining characters as long as the filter is shorter than the command name.
|
||||
// We will have remaining characters as long as the filter is shorter than the item name.
|
||||
auto sizeToReport = commandName.size() - nextOffsetToReport;
|
||||
if (sizeToReport > 0)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Calculates a "weighting" by which should be used to order a command
|
||||
// - 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
|
||||
@@ -159,7 +159,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// 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 command should not be shown. If all the
|
||||
// - 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.
|
||||
@@ -216,10 +216,10 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Function Description:
|
||||
// - Implementation of Compare for FilteredCommand interface.
|
||||
// Compares firs command with the second command, first by weight, then by name.
|
||||
// In the case of a tie prefers the first command
|
||||
// Compares first instance of the interface with the second instance, first by weight, then by name.
|
||||
// In the case of a tie prefers the first instance.
|
||||
// Arguments:
|
||||
// - other: another instance of Filtered Command interface
|
||||
// - other: another instance of FilteredCommand interface
|
||||
// Return Value:
|
||||
// - Returns true if the first is "bigger" (aka should appear first)
|
||||
int FilteredCommand::Compare(winrt::TerminalApp::FilteredCommand const& first, winrt::TerminalApp::FilteredCommand const& second)
|
||||
@@ -229,8 +229,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (firstWeight == secondWeight)
|
||||
{
|
||||
std::wstring_view firstName{ first.Command().Name() };
|
||||
std::wstring_view secondName{ second.Command().Name() };
|
||||
std::wstring_view firstName{ first.Item().Name() };
|
||||
std::wstring_view secondName{ second.Item().Name() };
|
||||
return lstrcmpi(firstName.data(), secondName.data()) < 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,14 @@ namespace winrt::TerminalApp::implementation
|
||||
struct FilteredCommand : FilteredCommandT<FilteredCommand>
|
||||
{
|
||||
FilteredCommand() = default;
|
||||
FilteredCommand(Microsoft::Terminal::Settings::Model::Command const& command);
|
||||
FilteredCommand(winrt::TerminalApp::PaletteItem const& item);
|
||||
|
||||
void UpdateFilter(winrt::hstring const& filter);
|
||||
|
||||
static int Compare(winrt::TerminalApp::FilteredCommand const& first, winrt::TerminalApp::FilteredCommand const& second);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
OBSERVABLE_GETSET_PROPERTY(Microsoft::Terminal::Settings::Model::Command, Command, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::TerminalApp::PaletteItem, Item, _PropertyChangedHandlers, nullptr);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Filter, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedName, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(int, Weight, _PropertyChangedHandlers);
|
||||
@@ -33,7 +33,7 @@ namespace winrt::TerminalApp::implementation
|
||||
private:
|
||||
winrt::TerminalApp::HighlightedText _computeHighlightedName();
|
||||
int _computeWeight();
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _commandChangedRevoker;
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _itemChangedRevoker;
|
||||
|
||||
friend class TerminalAppLocalTests::FilteredCommandTests;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "IDirectKeyListener.idl";
|
||||
import "ShortcutActionDispatch.idl";
|
||||
import "PaletteItem.idl";
|
||||
import "HighlightedTextControl.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
@@ -10,9 +9,9 @@ namespace TerminalApp
|
||||
[default_interface] runtimeclass FilteredCommand : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
FilteredCommand();
|
||||
FilteredCommand(Microsoft.Terminal.Settings.Model.Command command);
|
||||
FilteredCommand(PaletteItem item);
|
||||
|
||||
Microsoft.Terminal.Settings.Model.Command Command { get; };
|
||||
PaletteItem Item { get; };
|
||||
String Filter;
|
||||
HighlightedText HighlightedName { get; };
|
||||
Int32 Weight;
|
||||
|
||||
@@ -23,7 +23,8 @@ namespace winrt::TerminalApp::implementation
|
||||
Foundation::IInspectable const& /* parameter */,
|
||||
hstring const& /* language */)
|
||||
{
|
||||
const auto& hasNestedCommands = winrt::unbox_value_or<bool>(value, false);
|
||||
const auto paletteItem{ value.try_as<winrt::TerminalApp::ActionPaletteItem>() };
|
||||
const auto& hasNestedCommands = paletteItem && paletteItem.Command().HasNestedCommands();
|
||||
return winrt::box_value(hasNestedCommands ? Visibility::Visible : Visibility::Collapsed);
|
||||
}
|
||||
|
||||
|
||||
18
src/cascadia/TerminalApp/PaletteItem.cpp
Normal file
18
src/cascadia/TerminalApp/PaletteItem.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// 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::TerminalControl;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Windows::System;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
}
|
||||
19
src/cascadia/TerminalApp/PaletteItem.h
Normal file
19
src/cascadia/TerminalApp/PaletteItem.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
#include "inc/cppwinrt_utils.h"
|
||||
#include "PaletteItem.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct PaletteItem : PaletteItemT<PaletteItem>
|
||||
{
|
||||
public:
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Name, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Icon, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, KeyChordText, _PropertyChangedHandlers);
|
||||
};
|
||||
}
|
||||
12
src/cascadia/TerminalApp/PaletteItem.idl
Normal file
12
src/cascadia/TerminalApp/PaletteItem.idl
Normal file
@@ -0,0 +1,12 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ using namespace TerminalApp;
|
||||
|
||||
static const int PaneBorderSize = 2;
|
||||
static const int CombinedPaneBorderSize = 2 * PaneBorderSize;
|
||||
static const float Half = 0.50f;
|
||||
|
||||
// WARNING: Don't do this! This won't work
|
||||
// Duration duration{ std::chrono::milliseconds{ 200 } };
|
||||
@@ -130,7 +129,7 @@ void Pane::Relayout()
|
||||
// decreasing the size of our first child.
|
||||
// Return Value:
|
||||
// - false if we couldn't resize this pane in the given direction, else true.
|
||||
bool Pane::_Resize(const Direction& direction)
|
||||
bool Pane::_Resize(const ResizeDirection& direction)
|
||||
{
|
||||
if (!DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
@@ -138,7 +137,7 @@ bool Pane::_Resize(const Direction& direction)
|
||||
}
|
||||
|
||||
float amount = .05f;
|
||||
if (direction == Direction::Right || direction == Direction::Down)
|
||||
if (direction == ResizeDirection::Right || direction == ResizeDirection::Down)
|
||||
{
|
||||
amount = -amount;
|
||||
}
|
||||
@@ -171,7 +170,7 @@ bool Pane::_Resize(const Direction& direction)
|
||||
// - direction: The direction to move the separator in.
|
||||
// Return Value:
|
||||
// - true if we or a child handled this resize request.
|
||||
bool Pane::ResizePane(const Direction& direction)
|
||||
bool Pane::ResizePane(const ResizeDirection& direction)
|
||||
{
|
||||
// If we're a leaf, do nothing. We can't possibly have a descendant with a
|
||||
// separator the correct direction.
|
||||
@@ -223,14 +222,14 @@ bool Pane::ResizePane(const Direction& direction)
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - true if we handled this focus move request.
|
||||
bool Pane::_NavigateFocus(const Direction& direction)
|
||||
bool Pane::_NavigateFocus(const FocusDirection& direction)
|
||||
{
|
||||
if (!DirectionMatchesSplit(direction, _splitState))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool focusSecond = (direction == Direction::Right) || (direction == Direction::Down);
|
||||
const bool focusSecond = (direction == FocusDirection::Right) || (direction == FocusDirection::Down);
|
||||
|
||||
const auto newlyFocusedChild = focusSecond ? _secondChild : _firstChild;
|
||||
|
||||
@@ -261,7 +260,7 @@ bool Pane::_NavigateFocus(const Direction& direction)
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - true if we or a child handled this focus move request.
|
||||
bool Pane::NavigateFocus(const Direction& direction)
|
||||
bool Pane::NavigateFocus(const FocusDirection& direction)
|
||||
{
|
||||
// If we're a leaf, do nothing. We can't possibly have a descendant with a
|
||||
// separator the correct direction.
|
||||
@@ -655,9 +654,10 @@ void Pane::_CloseChild(const bool closeFirst)
|
||||
// inherited from us, so the flag will be set for both children.
|
||||
_borders = _firstChild->_borders & _secondChild->_borders;
|
||||
|
||||
// take the control and profile of the pane that _wasn't_ closed.
|
||||
// take the control, profile and id of the pane that _wasn't_ closed.
|
||||
_control = remainingChild->_control;
|
||||
_profile = remainingChild->_profile;
|
||||
_id = remainingChild->Id();
|
||||
|
||||
// Add our new event handler before revoking the old one.
|
||||
_connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler });
|
||||
@@ -1215,32 +1215,6 @@ void Pane::_SetupEntranceAnimation()
|
||||
setupAnimation(secondSize, false);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Determines whether the pane can be split
|
||||
// Arguments:
|
||||
// - splitType: what type of split we want to create.
|
||||
// Return Value:
|
||||
// - True if the pane can be split. False otherwise.
|
||||
bool Pane::CanSplit(SplitState splitType)
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
return _CanSplit(splitType);
|
||||
}
|
||||
|
||||
if (_firstChild->_HasFocusedChild())
|
||||
{
|
||||
return _firstChild->CanSplit(splitType);
|
||||
}
|
||||
|
||||
if (_secondChild->_HasFocusedChild())
|
||||
{
|
||||
return _secondChild->CanSplit(splitType);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This is a helper to determine if a given Pane can be split, but without
|
||||
// using the ActualWidth() and ActualHeight() methods. This is used during
|
||||
@@ -1271,12 +1245,15 @@ bool Pane::CanSplit(SplitState splitType)
|
||||
// - This method is highly similar to Pane::PreCalculateAutoSplit
|
||||
std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> target,
|
||||
SplitState splitType,
|
||||
const float splitSize,
|
||||
const winrt::Windows::Foundation::Size availableSpace) const
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
if (target.get() == this)
|
||||
{
|
||||
const auto firstPrecent = 1.0f - splitSize;
|
||||
const auto secondPercent = splitSize;
|
||||
// If this pane is a leaf, and it's the pane we're looking for, use
|
||||
// the available space to calculate which direction to split in.
|
||||
const Size minSize = _GetMinSize();
|
||||
@@ -1289,17 +1266,19 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
|
||||
else if (splitType == SplitState::Vertical)
|
||||
{
|
||||
const auto widthMinusSeparator = availableSpace.Width - CombinedPaneBorderSize;
|
||||
const auto newWidth = widthMinusSeparator * Half;
|
||||
const auto newFirstWidth = widthMinusSeparator * firstPrecent;
|
||||
const auto newSecondWidth = widthMinusSeparator * secondPercent;
|
||||
|
||||
return { newWidth > minSize.Width };
|
||||
return { newFirstWidth > minSize.Width && newSecondWidth > minSize.Width };
|
||||
}
|
||||
|
||||
else if (splitType == SplitState::Horizontal)
|
||||
{
|
||||
const auto heightMinusSeparator = availableSpace.Height - CombinedPaneBorderSize;
|
||||
const auto newHeight = heightMinusSeparator * Half;
|
||||
const auto newFirstHeight = heightMinusSeparator * firstPrecent;
|
||||
const auto newSecondHeight = heightMinusSeparator * secondPercent;
|
||||
|
||||
return { newHeight > minSize.Height };
|
||||
return { newFirstHeight > minSize.Height && newSecondHeight > minSize.Height };
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1328,8 +1307,8 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
|
||||
(availableSpace.Height - firstHeight) - PaneBorderSize :
|
||||
availableSpace.Height;
|
||||
|
||||
const auto firstResult = _firstChild->PreCalculateCanSplit(target, splitType, { firstWidth, firstHeight });
|
||||
return firstResult.has_value() ? firstResult : _secondChild->PreCalculateCanSplit(target, splitType, { secondWidth, secondHeight });
|
||||
const auto firstResult = _firstChild->PreCalculateCanSplit(target, splitType, splitSize, { firstWidth, firstHeight });
|
||||
return firstResult.has_value() ? firstResult : _secondChild->PreCalculateCanSplit(target, splitType, splitSize, { secondWidth, secondHeight });
|
||||
}
|
||||
|
||||
// We should not possibly be getting here - both the above branches should
|
||||
@@ -1347,23 +1326,26 @@ std::optional<bool> Pane::PreCalculateCanSplit(const std::shared_ptr<Pane> targe
|
||||
// - control: A TermControl to use in the new pane.
|
||||
// Return Value:
|
||||
// - The two newly created Panes
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitState splitType, const GUID& profile, const TermControl& control)
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::Split(SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const TermControl& control)
|
||||
{
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
if (_firstChild->_HasFocusedChild())
|
||||
{
|
||||
return _firstChild->Split(splitType, profile, control);
|
||||
return _firstChild->Split(splitType, splitSize, profile, control);
|
||||
}
|
||||
else if (_secondChild->_HasFocusedChild())
|
||||
{
|
||||
return _secondChild->Split(splitType, profile, control);
|
||||
return _secondChild->Split(splitType, splitSize, profile, control);
|
||||
}
|
||||
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
|
||||
return _Split(splitType, profile, control);
|
||||
return _Split(splitType, splitSize, profile, control);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1391,45 +1373,6 @@ SplitState Pane::_convertAutomaticSplitState(const SplitState& splitType) const
|
||||
return splitType;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Determines whether the pane can be split.
|
||||
// Arguments:
|
||||
// - splitType: what type of split we want to create.
|
||||
// Return Value:
|
||||
// - True if the pane can be split. False otherwise.
|
||||
bool Pane::_CanSplit(SplitState splitType)
|
||||
{
|
||||
const Size actualSize{ gsl::narrow_cast<float>(_root.ActualWidth()),
|
||||
gsl::narrow_cast<float>(_root.ActualHeight()) };
|
||||
|
||||
const Size minSize = _GetMinSize();
|
||||
|
||||
auto actualSplitType = _convertAutomaticSplitState(splitType);
|
||||
|
||||
if (actualSplitType == SplitState::None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (actualSplitType == SplitState::Vertical)
|
||||
{
|
||||
const auto widthMinusSeparator = actualSize.Width - CombinedPaneBorderSize;
|
||||
const auto newWidth = widthMinusSeparator * Half;
|
||||
|
||||
return newWidth > minSize.Width;
|
||||
}
|
||||
|
||||
if (actualSplitType == SplitState::Horizontal)
|
||||
{
|
||||
const auto heightMinusSeparator = actualSize.Height - CombinedPaneBorderSize;
|
||||
const auto newHeight = heightMinusSeparator * Half;
|
||||
|
||||
return newHeight > minSize.Height;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Does the bulk of the work of creating a new split. Initializes our UI,
|
||||
// creates a new Pane to host the control, registers event handlers.
|
||||
@@ -1439,7 +1382,10 @@ bool Pane::_CanSplit(SplitState splitType)
|
||||
// - control: A TermControl to use in the new pane.
|
||||
// Return Value:
|
||||
// - The two newly created Panes
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState splitType, const GUID& profile, const TermControl& control)
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const TermControl& control)
|
||||
{
|
||||
if (splitType == SplitState::None)
|
||||
{
|
||||
@@ -1464,7 +1410,7 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState
|
||||
_gotFocusRevoker.revoke();
|
||||
|
||||
_splitState = actualSplitType;
|
||||
_desiredSplitPosition = Half;
|
||||
_desiredSplitPosition = 1.0f - splitSize;
|
||||
|
||||
// Remove any children we currently have. We can't add the existing
|
||||
// TermControl to a new grid until we do this.
|
||||
@@ -1493,6 +1439,9 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitState
|
||||
|
||||
_SetupEntranceAnimation();
|
||||
|
||||
// Clear out our ID, only leaves should have IDs
|
||||
_id = {};
|
||||
|
||||
return { _firstChild, _secondChild };
|
||||
}
|
||||
|
||||
@@ -1566,6 +1515,47 @@ void Pane::Restore(std::shared_ptr<Pane> zoomedPane)
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Retrieves the ID of this pane
|
||||
// - NOTE: The caller should make sure that this pane is a leaf,
|
||||
// otherwise the ID value will not make sense (leaves have IDs, parents do not)
|
||||
// Return Value:
|
||||
// - The ID of this pane
|
||||
uint16_t Pane::Id() noexcept
|
||||
{
|
||||
return _id.value();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets this pane's ID
|
||||
// - Panes are given IDs upon creation by TerminalTab
|
||||
// Arguments:
|
||||
// - The number to set this pane's ID to
|
||||
void Pane::Id(uint16_t id) noexcept
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Recursive function that focuses a pane with the given ID
|
||||
// Arguments:
|
||||
// - The ID of the pane we want to focus
|
||||
void Pane::FocusPane(const uint16_t id)
|
||||
{
|
||||
if (_IsLeaf() && id == _id)
|
||||
{
|
||||
_control.Focus(FocusState::Programmatic);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_firstChild && _secondChild)
|
||||
{
|
||||
_firstChild->FocusPane(id);
|
||||
_secondChild->FocusPane(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the size in pixels of each of our children, given the full size they
|
||||
// should fill. Since these children own their own separators (borders), this
|
||||
|
||||
@@ -55,17 +55,19 @@ public:
|
||||
const GUID& profile);
|
||||
void ResizeContent(const winrt::Windows::Foundation::Size& newSize);
|
||||
void Relayout();
|
||||
bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction);
|
||||
bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction);
|
||||
bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
|
||||
bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
|
||||
bool CanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType);
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitState> PreCalculateAutoSplit(const std::shared_ptr<Pane> target, const winrt::Windows::Foundation::Size parentSize) const;
|
||||
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitState> PreCalculateAutoSplit(const std::shared_ptr<Pane> target,
|
||||
const winrt::Windows::Foundation::Size parentSize) const;
|
||||
std::optional<bool> PreCalculateCanSplit(const std::shared_ptr<Pane> target,
|
||||
winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
|
||||
const float splitSize,
|
||||
const winrt::Windows::Foundation::Size availableSpace) const;
|
||||
void Shutdown();
|
||||
void Close();
|
||||
@@ -75,6 +77,10 @@ public:
|
||||
void Maximize(std::shared_ptr<Pane> zoomedPane);
|
||||
void Restore(std::shared_ptr<Pane> zoomedPane);
|
||||
|
||||
uint16_t Id() noexcept;
|
||||
void Id(uint16_t id) noexcept;
|
||||
void FocusPane(const uint16_t id);
|
||||
|
||||
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
|
||||
DECLARE_EVENT(GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
DECLARE_EVENT(PaneRaiseVisualBell, _PaneRaiseVisualBellHandlers, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
@@ -95,6 +101,8 @@ private:
|
||||
winrt::Microsoft::Terminal::Settings::Model::SplitState _splitState{ winrt::Microsoft::Terminal::Settings::Model::SplitState::None };
|
||||
float _desiredSplitPosition;
|
||||
|
||||
std::optional<uint16_t> _id;
|
||||
|
||||
bool _lastActive{ false };
|
||||
std::optional<GUID> _profile{ std::nullopt };
|
||||
winrt::event_token _connectionStateChangedToken{ 0 };
|
||||
@@ -114,8 +122,8 @@ private:
|
||||
bool _HasFocusedChild() const noexcept;
|
||||
void _SetupChildCloseHandlers();
|
||||
|
||||
bool _CanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType);
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType,
|
||||
const float splitSize,
|
||||
const GUID& profile,
|
||||
const winrt::Microsoft::Terminal::TerminalControl::TermControl& control);
|
||||
|
||||
@@ -124,8 +132,8 @@ private:
|
||||
void _SetupEntranceAnimation();
|
||||
void _UpdateBorders();
|
||||
|
||||
bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction);
|
||||
bool _NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction);
|
||||
bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
|
||||
bool _NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
|
||||
void _CloseChild(const bool closeFirst);
|
||||
winrt::fire_and_forget _CloseChildRoutine(const bool closeFirst);
|
||||
@@ -156,15 +164,15 @@ private:
|
||||
// - This is used for pane resizing (which will need a pane separator
|
||||
// that's perpendicular to the direction to be able to move the separator
|
||||
// in that direction).
|
||||
// - Additionally, it will be used for moving focus between panes, which
|
||||
// again happens _across_ a separator.
|
||||
// - Also used for moving focus between panes, which again happens _across_ a separator.
|
||||
// Arguments:
|
||||
// - direction: The Direction to compare
|
||||
// - splitType: The winrt::TerminalApp::SplitState to compare
|
||||
// Return Value:
|
||||
// - true iff the direction is perpendicular to the splitType. False for
|
||||
// winrt::TerminalApp::SplitState::None.
|
||||
static constexpr bool DirectionMatchesSplit(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction,
|
||||
template<typename T>
|
||||
static constexpr bool DirectionMatchesSplit(const T& direction,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::SplitState& splitType)
|
||||
{
|
||||
if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::None)
|
||||
@@ -173,13 +181,13 @@ private:
|
||||
}
|
||||
else if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::Horizontal)
|
||||
{
|
||||
return direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Up ||
|
||||
direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Down;
|
||||
return direction == T::Up ||
|
||||
direction == T::Down;
|
||||
}
|
||||
else if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::Vertical)
|
||||
{
|
||||
return direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Left ||
|
||||
direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Right;
|
||||
return direction == T::Left ||
|
||||
direction == T::Right;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
@@ -26,36 +26,36 @@
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
@@ -249,6 +249,10 @@
|
||||
<value>Found a command with an invalid "colorScheme". This command will be ignored. Make sure that when setting a "colorScheme", the value matches the "name" of a color scheme in the "schemes" list.</value>
|
||||
<comment>{Locked="\"colorScheme\"","\"name\"","\"schemes\""}</comment>
|
||||
</data>
|
||||
<data name="InvalidSplitSize" xml:space="preserve">
|
||||
<value>Found a "splitPane" command with an invalid "size". This command will be ignored. Make sure the size is between 0 and 1, exclusive.</value>
|
||||
<comment>{Locked="\"splitPane\"","\"size\""}</comment>
|
||||
</data>
|
||||
<data name="CmdCommandArgDesc" xml:space="preserve">
|
||||
<value>An optional command, with arguments, to be spawned in the new tab or pane</value>
|
||||
</data>
|
||||
@@ -268,6 +272,9 @@
|
||||
<data name="CmdFocusTabTargetArgDesc" xml:space="preserve">
|
||||
<value>Move focus the tab at the given index</value>
|
||||
</data>
|
||||
<data name="CmdSplitPaneSizeArgDesc" xml:space="preserve">
|
||||
<value>Specify the size as a percentage of the parent pane. Valid values are between (0,1), exclusive.</value>
|
||||
</data>
|
||||
<data name="CmdNewTabDesc" xml:space="preserve">
|
||||
<value>Create a new tab</value>
|
||||
</data>
|
||||
@@ -413,6 +420,13 @@
|
||||
<data name="CommandPalette_NoMatchesText.Text" xml:space="preserve">
|
||||
<value>No matching commands</value>
|
||||
</data>
|
||||
<data name="CommandPalette_ParsedCommandLine" xml:space="preserve">
|
||||
<value>Executing command line will invoke the following commands:</value>
|
||||
<comment>Will be followed by a list of strings describing parsed commands</comment>
|
||||
</data>
|
||||
<data name="CommandPalette_FailedParsingCommandLine" xml:space="preserve">
|
||||
<value>Failed parsing command line:</value>
|
||||
</data>
|
||||
<data name="CommandPaletteControlName" xml:space="preserve">
|
||||
<value>Command Palette</value>
|
||||
</data>
|
||||
@@ -486,6 +500,9 @@
|
||||
<data name="CouldNotOpenUriDialog.PrimaryButtonText" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="SettingsTab" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="FailedToWriteToSettings" xml:space="preserve">
|
||||
<value>We could not write to your settings file. Check the permissions on that file to ensure that the read-only flag is not set and that write access is granted.</value>
|
||||
</data>
|
||||
@@ -510,4 +527,4 @@
|
||||
<data name="NoticeWarning" xml:space="preserve">
|
||||
<value>Warning</value>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
92
src/cascadia/TerminalApp/SettingsTab.cpp
Normal file
92
src/cascadia/TerminalApp/SettingsTab.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include <LibraryResources.h>
|
||||
#include "SettingsTab.h"
|
||||
#include "SettingsTab.g.cpp"
|
||||
#include "Utils.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Microsoft::Terminal::TerminalControl;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Editor;
|
||||
using namespace winrt::Windows::System;
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
namespace WUX = Windows::UI::Xaml;
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
SettingsTab::SettingsTab(MainPage settingsUI)
|
||||
{
|
||||
Content(settingsUI);
|
||||
|
||||
_MakeTabViewItem();
|
||||
_CreateContextMenu();
|
||||
_CreateIcon();
|
||||
}
|
||||
|
||||
void SettingsTab::UpdateSettings(CascadiaSettings settings)
|
||||
{
|
||||
auto settingsUI{ Content().as<MainPage>() };
|
||||
settingsUI.UpdateSettings(settings);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Focus the settings UI
|
||||
// Arguments:
|
||||
// - focusState: The FocusState mode by which focus is to be obtained.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void SettingsTab::Focus(WUX::FocusState focusState)
|
||||
{
|
||||
_focusState = focusState;
|
||||
|
||||
if (_focusState != FocusState::Unfocused)
|
||||
{
|
||||
Content().as<WUX::Controls::Page>().Focus(focusState);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Initializes a TabViewItem for this Tab instance.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void SettingsTab::_MakeTabViewItem()
|
||||
{
|
||||
TabViewItem(::winrt::MUX::Controls::TabViewItem{});
|
||||
Title(RS_(L"SettingsTab"));
|
||||
TabViewItem().Header(winrt::box_value(Title()));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Set the icon on the TabViewItem for this tab.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget SettingsTab::_CreateIcon()
|
||||
{
|
||||
auto weakThis{ get_weak() };
|
||||
|
||||
co_await winrt::resume_foreground(TabViewItem().Dispatcher());
|
||||
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
auto fontFamily = winrt::WUX::Media::FontFamily(L"Segoe MDL2 Assets");
|
||||
auto glyph = L"\xE713"; // This is the Setting icon (looks like a gear)
|
||||
|
||||
// The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
|
||||
Icon(glyph);
|
||||
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(glyph));
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/cascadia/TerminalApp/SettingsTab.h
Normal file
39
src/cascadia/TerminalApp/SettingsTab.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- SettingsTab.h
|
||||
|
||||
Abstract:
|
||||
- The SettingsTab is a tab whose content is a Settings UI control. They can
|
||||
coexist in a TabView with all other types of tabs, like the TerminalTab.
|
||||
There should only be at most one SettingsTab open at any given time.
|
||||
|
||||
Author(s):
|
||||
- Leon Liang - October 2020
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include "TabBase.h"
|
||||
#include "SettingsTab.g.h"
|
||||
#include <winrt/TerminalApp.h>
|
||||
#include <winrt/Microsoft.Terminal.Settings.Editor.h>
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct SettingsTab : SettingsTabT<SettingsTab, TabBase>
|
||||
{
|
||||
public:
|
||||
SettingsTab(winrt::Microsoft::Terminal::Settings::Editor::MainPage settingsUI);
|
||||
|
||||
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
|
||||
|
||||
private:
|
||||
void _MakeTabViewItem();
|
||||
winrt::fire_and_forget _CreateIcon();
|
||||
};
|
||||
}
|
||||
12
src/cascadia/TerminalApp/SettingsTab.idl
Normal file
12
src/cascadia/TerminalApp/SettingsTab.idl
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "TabBase.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass SettingsTab : TabBase
|
||||
{
|
||||
void UpdateSettings(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,16 @@ namespace winrt::TerminalApp::implementation
|
||||
_ScrollDownPageHandlers(*this, eventArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
case ShortcutAction::ScrollToTop:
|
||||
{
|
||||
_ScrollToTopHandlers(*this, eventArgs);
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ScrollToBottom:
|
||||
{
|
||||
_ScrollToBottomHandlers(*this, eventArgs);
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::NextTab:
|
||||
{
|
||||
_NextTabHandlers(*this, eventArgs);
|
||||
@@ -167,9 +176,9 @@ namespace winrt::TerminalApp::implementation
|
||||
_ResetFontSizeHandlers(*this, eventArgs);
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ToggleRetroEffect:
|
||||
case ShortcutAction::ToggleShaderEffects:
|
||||
{
|
||||
_ToggleRetroEffectHandlers(*this, eventArgs);
|
||||
_ToggleShaderEffectsHandlers(*this, eventArgs);
|
||||
break;
|
||||
}
|
||||
case ShortcutAction::ToggleFocusMode:
|
||||
|
||||
@@ -43,11 +43,13 @@ namespace winrt::TerminalApp::implementation
|
||||
TYPED_EVENT(ScrollDown, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ScrollUpPage, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ScrollDownPage, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ScrollToTop, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ScrollToBottom, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(OpenSettings, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ResizePane, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(Find, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(MoveFocus, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ToggleRetroEffect, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ToggleShaderEffects, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ToggleFocusMode, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ToggleFullscreen, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
TYPED_EVENT(ToggleAlwaysOnTop, TerminalApp::ShortcutActionDispatch, Microsoft::Terminal::Settings::Model::ActionEventArgs);
|
||||
|
||||
@@ -29,11 +29,13 @@ namespace TerminalApp
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ScrollDown;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ScrollUpPage;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ScrollDownPage;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ScrollToTop;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ScrollToBottom;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> OpenSettings;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ResizePane;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> Find;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> MoveFocus;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ToggleRetroEffect;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ToggleShaderEffects;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ToggleFocusMode;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ToggleFullscreen;
|
||||
event Windows.Foundation.TypedEventHandler<ShortcutActionDispatch, Microsoft.Terminal.Settings.Model.ActionEventArgs> ToggleAlwaysOnTop;
|
||||
|
||||
@@ -138,7 +138,6 @@ namespace winrt::TerminalApp::implementation
|
||||
TabViewIndex(idx);
|
||||
TabViewNumTabs(numTabs);
|
||||
_EnableCloseMenuItems();
|
||||
SwitchToTabCommand().Action().Args().as<SwitchToTabArgs>().TabIndex(idx);
|
||||
}
|
||||
|
||||
void TabBase::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch)
|
||||
|
||||
@@ -28,14 +28,12 @@ namespace winrt::TerminalApp::implementation
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
|
||||
// This is needed since Tab is going to be managing its own SwitchToTab command.
|
||||
GETSET_PROPERTY(uint32_t, TabViewIndex, 0);
|
||||
// The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector.
|
||||
GETSET_PROPERTY(uint32_t, TabViewNumTabs, 0);
|
||||
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Icon, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::Command, SwitchToTabCommand, _PropertyChangedHandlers, nullptr);
|
||||
GETSET_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewItem, TabViewItem, nullptr);
|
||||
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, _PropertyChangedHandlers, nullptr);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace TerminalApp
|
||||
{
|
||||
String Title { get; };
|
||||
String Icon { get; };
|
||||
Microsoft.Terminal.Settings.Model.Command SwitchToTabCommand;
|
||||
|
||||
Microsoft.UI.Xaml.Controls.TabViewItem TabViewItem { get; };
|
||||
Windows.UI.Xaml.FrameworkElement Content { get; };
|
||||
Windows.UI.Xaml.FocusState FocusState { get; };
|
||||
|
||||
@@ -59,6 +59,13 @@ namespace winrt::TerminalApp::implementation
|
||||
HeaderRenamerTextBox().Text(Title());
|
||||
HeaderRenamerTextBox().SelectAll();
|
||||
HeaderRenamerTextBox().Focus(Windows::UI::Xaml::FocusState::Programmatic);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
|
||||
"TabRenamerOpened",
|
||||
TraceLoggingDescription("Event emitted when the tab renamer is opened"),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -68,6 +75,18 @@ namespace winrt::TerminalApp::implementation
|
||||
void TabHeaderControl::RenameBoxLostFocusHandler(Windows::Foundation::IInspectable const& /*sender*/,
|
||||
Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
|
||||
{
|
||||
// Log the data here, rather than in _CloseRenameBox. If we do it there,
|
||||
// it'll get fired twice, once when the key is pressed to commit/cancel,
|
||||
// and then again when the focus is lost
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
|
||||
"TabRenamerClosed",
|
||||
TraceLoggingDescription("Event emitted when the tab renamer is closed"),
|
||||
TraceLoggingBoolean(_renameCancelled, "CancelledRename", "True if the user cancelled the rename, false if they committed."),
|
||||
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
|
||||
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
|
||||
|
||||
_CloseRenameBox();
|
||||
if (!_renameCancelled)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace winrt::TerminalApp::implementation
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
OBSERVABLE_GETSET_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(bool, IsPaneZoomed, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(bool, IsProgressRingActive, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(bool, IsProgressRingIndeterminate, _PropertyChangedHandlers);
|
||||
OBSERVABLE_GETSET_PROPERTY(uint32_t, ProgressValue, _PropertyChangedHandlers);
|
||||
|
||||
private:
|
||||
bool _receivedKeyDown{ false };
|
||||
|
||||
@@ -9,6 +9,9 @@ namespace TerminalApp
|
||||
{
|
||||
String Title { get; set; };
|
||||
Boolean IsPaneZoomed { get; set; };
|
||||
Boolean IsProgressRingActive { get; set; };
|
||||
Boolean IsProgressRingIndeterminate { get; set; };
|
||||
UInt32 ProgressValue { get; set; };
|
||||
|
||||
TabHeaderControl();
|
||||
void BeginRename();
|
||||
|
||||
@@ -1,16 +1,31 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information. -->
|
||||
|
||||
<UserControl
|
||||
x:Class="TerminalApp.TabHeaderControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<StackPanel x:Name="HeaderStackPanel"
|
||||
Orientation="Horizontal">
|
||||
<mux:ProgressRing x:Name="HeaderProgressRing"
|
||||
IsActive="{x:Bind IsProgressRingActive, Mode=OneWay}"
|
||||
Visibility="{x:Bind IsProgressRingActive, Mode=OneWay}"
|
||||
IsIndeterminate="{x:Bind IsProgressRingIndeterminate, Mode=OneWay}"
|
||||
Value="{x:Bind ProgressValue, Mode=OneWay}"
|
||||
MinHeight="0"
|
||||
MinWidth="0"
|
||||
Height="15"
|
||||
Width="15"
|
||||
Margin="-7.5,0,8,0"/>
|
||||
<!--We want the progress ring to 'replace' the tab icon, but we don't have control
|
||||
over the tab icon here (the tab view item does) - so we hide the tab icon there
|
||||
and use a negative margin for the progress ring here to put it where the icon would be-->
|
||||
<FontIcon x:Name="HeaderZoomIcon"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Visibility="{x:Bind IsPaneZoomed, Mode=OneWay}"
|
||||
|
||||
45
src/cascadia/TerminalApp/TabPaletteItem.cpp
Normal file
45
src/cascadia/TerminalApp/TabPaletteItem.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "TabPaletteItem.h"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
#include "TabPaletteItem.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
|
||||
{
|
||||
TabPaletteItem::TabPaletteItem(winrt::TerminalApp::TabBase const& 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<TabBase>() };
|
||||
|
||||
if (item && senderTab)
|
||||
{
|
||||
auto changedProperty = e.PropertyName();
|
||||
if (changedProperty == L"Title")
|
||||
{
|
||||
item->Name(senderTab.Title());
|
||||
}
|
||||
else if (changedProperty == L"Icon")
|
||||
{
|
||||
item->Icon(senderTab.Icon());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
31
src/cascadia/TerminalApp/TabPaletteItem.h
Normal file
31
src/cascadia/TerminalApp/TabPaletteItem.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PaletteItem.h"
|
||||
#include "TabPaletteItem.g.h"
|
||||
#include "inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct TabPaletteItem : TabPaletteItemT<TabPaletteItem, PaletteItem>
|
||||
{
|
||||
TabPaletteItem() = default;
|
||||
TabPaletteItem(winrt::TerminalApp::TabBase const& tab);
|
||||
|
||||
winrt::TerminalApp::TabBase Tab() const noexcept
|
||||
{
|
||||
return _tab.get();
|
||||
}
|
||||
|
||||
private:
|
||||
winrt::weak_ref<winrt::TerminalApp::TabBase> _tab;
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _tabChangedRevoker;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(TabPaletteItem);
|
||||
}
|
||||
15
src/cascadia/TerminalApp/TabPaletteItem.idl
Normal file
15
src/cascadia/TerminalApp/TabPaletteItem.idl
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "PaletteItem.idl";
|
||||
import "TabBase.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass TabPaletteItem : PaletteItem
|
||||
{
|
||||
TabPaletteItem(TabBase tab);
|
||||
|
||||
TabBase Tab { get; };
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.props')" />
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
<ClCompile>
|
||||
@@ -69,16 +69,23 @@
|
||||
</ItemGroup>
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ActionPaletteItem.h" />
|
||||
<ClInclude Include="App.base.h" />
|
||||
<ClInclude Include="AppCommandlineArgs.h" />
|
||||
<ClInclude Include="Commandline.h" />
|
||||
<ClInclude Include="CommandLinePaletteItem.h" />
|
||||
<ClInclude Include="Jumplist.h" />
|
||||
<ClInclude Include="MinMaxCloseControl.h">
|
||||
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsTab.h">
|
||||
<DependentUpon>SettingsTab.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PaletteItem.h" />
|
||||
<ClInclude Include="TabBase.h">
|
||||
<DependentUpon>TabBase.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TabPaletteItem.h" />
|
||||
<ClInclude Include="TerminalTab.h">
|
||||
<DependentUpon>TerminalTab.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
@@ -112,9 +119,6 @@
|
||||
<ClInclude Include="HasNestedCommandsVisibilityConverter.h">
|
||||
<DependentUpon>HasNestedCommandsVisibilityConverter.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IconPathConverter.h">
|
||||
<DependentUpon>IconPathConverter.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Pane.h" />
|
||||
<ClInclude Include="ColorHelper.h" />
|
||||
<ClInclude Include="TerminalSettings.h">
|
||||
@@ -137,6 +141,8 @@
|
||||
</ItemGroup>
|
||||
<!-- ========================= Cpp Files ======================== -->
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ActionPaletteItem.cpp" />
|
||||
<ClCompile Include="CommandLinePaletteItem.cpp" />
|
||||
<ClCompile Include="init.cpp" />
|
||||
<ClCompile Include="AppCommandlineArgs.cpp" />
|
||||
<ClCompile Include="Commandline.cpp" />
|
||||
@@ -144,9 +150,14 @@
|
||||
<ClCompile Include="MinMaxCloseControl.cpp">
|
||||
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SettingsTab.cpp">
|
||||
<DependentUpon>SettingsTab.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PaletteItem.cpp" />
|
||||
<ClCompile Include="TabBase.cpp">
|
||||
<DependentUpon>TabBase.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TabPaletteItem.cpp" />
|
||||
<ClCompile Include="TerminalTab.cpp">
|
||||
<DependentUpon>TerminalTab.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
@@ -180,9 +191,6 @@
|
||||
<ClCompile Include="HasNestedCommandsVisibilityConverter.cpp">
|
||||
<DependentUpon>HasNestedCommandsVisibilityConverter.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IconPathConverter.cpp">
|
||||
<DependentUpon>IconPathConverter.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Pane.cpp" />
|
||||
<ClCompile Include="Pane.LayoutSizeNode.cpp" />
|
||||
<ClCompile Include="ColorHelper.cpp" />
|
||||
@@ -214,10 +222,14 @@
|
||||
<ItemGroup>
|
||||
<!-- If you add idl files here, make sure to include their implementation's
|
||||
header in TerminalApp.vcxproj (as well as in this file) -->
|
||||
<Midl Include="ActionPaletteItem.idl" />
|
||||
<Midl Include="CommandLinePaletteItem.idl" />
|
||||
<Midl Include="IDirectKeyListener.idl" />
|
||||
<Midl Include="App.idl">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Midl>
|
||||
<Midl Include="SettingsTab.idl" />
|
||||
<Midl Include="PaletteItem.idl" />
|
||||
<Midl Include="ShortcutActionDispatch.idl" />
|
||||
<Midl Include="AppKeyBindings.idl" />
|
||||
<Midl Include="AppLogic.idl" />
|
||||
@@ -226,6 +238,7 @@
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="TabBase.idl" />
|
||||
<Midl Include="TabPaletteItem.idl" />
|
||||
<Midl Include="TerminalTab.idl" />
|
||||
<Midl Include="TerminalPage.idl">
|
||||
<DependentUpon>TerminalPage.xaml</DependentUpon>
|
||||
@@ -259,7 +272,6 @@
|
||||
<Midl Include="FilteredCommand.idl" />
|
||||
<Midl Include="EmptyStringVisibilityConverter.idl" />
|
||||
<Midl Include="HasNestedCommandsVisibilityConverter.idl" />
|
||||
<Midl Include="IconPathConverter.idl" />
|
||||
<Midl Include="TerminalSettings.idl" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
@@ -307,6 +319,12 @@
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Terminal.Settings.Editor">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)Microsoft.Terminal.Settings.Editor\Microsoft.Terminal.Settings.Editor.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
<Private>false</Private>
|
||||
<CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Terminal.Settings.Model">
|
||||
<HintPath>$(OpenConsoleCommonOutDir)Microsoft.Terminal.Settings.Model\Microsoft.Terminal.Settings.Model.winmd</HintPath>
|
||||
<IsWinMDFile>true</IsWinMDFile>
|
||||
@@ -330,13 +348,13 @@
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Import Project="..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets" Condition="Exists('..\..\..\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.0.0\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.Toolkit.Win32.UI.XamlApplication.6.1.2\build\native\Microsoft.Toolkit.Win32.UI.XamlApplication.targets'))" />
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -31,9 +31,24 @@
|
||||
<ClCompile Include="Tab.cpp">
|
||||
<Filter>tab</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SettingsTab.cpp">
|
||||
<Filter>tab</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FilteredCommand.cpp">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ActionPaletteItem.cpp">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PaletteItem.cpp">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TabPaletteItem.cpp">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CommandLinePaletteItem.cpp">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HighlightedText.cpp">
|
||||
<Filter>highlightedText</Filter>
|
||||
</ClCompile>
|
||||
@@ -62,9 +77,24 @@
|
||||
<ClInclude Include="Tab.h">
|
||||
<Filter>tab</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsTab.h">
|
||||
<Filter>tab</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FilteredCommand.h">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ActionPaletteItem.h">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PaletteItem.h">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TabPaletteItem.h">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CommandLinePaletteItem.h">
|
||||
<Filter>commandPalette</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HighlightedText.h">
|
||||
<Filter>highlightedText</Filter>
|
||||
</ClInclude>
|
||||
@@ -86,6 +116,12 @@
|
||||
<Midl Include="TerminalSettings.idl">
|
||||
<Filter>settings</Filter>
|
||||
</Midl>
|
||||
<Midl Include="ITab.idl">
|
||||
<Filter>tab</Filter>
|
||||
</Midl>
|
||||
<Midl Include="SettingsTab.idl">
|
||||
<Filter>tab</Filter>
|
||||
</Midl>
|
||||
<Midl Include="TerminalTab.idl">
|
||||
<Filter>tab</Filter>
|
||||
</Midl>
|
||||
@@ -121,6 +157,21 @@
|
||||
<Page Include="CommandPalette.xaml">
|
||||
<Filter>commandPalette</Filter>
|
||||
</Page>
|
||||
<Midl Include="PaletteItem.idl">
|
||||
<Filter>commandPalette</Filter>
|
||||
</Midl>
|
||||
<Midl Include="TabPaletteItem.idl">
|
||||
<Filter>commandPalette</Filter>
|
||||
</Midl>
|
||||
<Midl Include="ActionPaletteItem.idl">
|
||||
<Filter>commandPalette</Filter>
|
||||
</Midl>
|
||||
<Midl Include="FilterableListItem.idl">
|
||||
<Filter>commandPalette</Filter>
|
||||
</Midl>
|
||||
<Midl Include="CommandLinePaletteItem.idl">
|
||||
<Filter>commandPalette</Filter>
|
||||
</Midl>
|
||||
<Page Include="HighlightedTextControl.xaml">
|
||||
<Filter>highlightedText</Filter>
|
||||
</Page>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "TabRowControl.h"
|
||||
#include "ColorHelper.h"
|
||||
#include "DebugTapConnection.h"
|
||||
#include "SettingsTab.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
@@ -43,7 +44,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TerminalPage::TerminalPage() :
|
||||
_tabs{ winrt::single_threaded_observable_vector<TerminalApp::TabBase>() },
|
||||
_mruTabActions{ winrt::single_threaded_vector<Command>() },
|
||||
_mruTabs{ winrt::single_threaded_vector<TerminalApp::TabBase>() },
|
||||
_startupActions{ winrt::single_threaded_vector<ActionAndArgs>() },
|
||||
_hostingHwnd{}
|
||||
{
|
||||
@@ -208,6 +209,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
page->_SplitPane(SplitState::Automatic,
|
||||
SplitType::Manual,
|
||||
0.5f,
|
||||
nullptr);
|
||||
}
|
||||
else
|
||||
@@ -226,7 +228,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
_tabContent.SizeChanged({ this, &TerminalPage::_OnContentSizeChanged });
|
||||
|
||||
CommandPalette().SetDispatch(*_actionDispatch);
|
||||
// When the visibility of the command palette changes to "collapsed",
|
||||
// the palette has been closed. Toss focus back to the currently active
|
||||
// control.
|
||||
@@ -236,6 +237,9 @@ namespace winrt::TerminalApp::implementation
|
||||
_CommandPaletteClosed(nullptr, nullptr);
|
||||
}
|
||||
});
|
||||
CommandPalette().DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested });
|
||||
CommandPalette().CommandLineExecutionRequested({ this, &TerminalPage::_OnCommandLineExecutionRequested });
|
||||
CommandPalette().SwitchToTabRequested({ this, &TerminalPage::_OnSwitchToTabRequested });
|
||||
|
||||
// Settings AllowDependentAnimations will affect whether animations are
|
||||
// enabled application-wide, so we don't need to check it each time we
|
||||
@@ -252,6 +256,49 @@ namespace winrt::TerminalApp::implementation
|
||||
_isAlwaysOnTop = _settings.GlobalSettings().AlwaysOnTop();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This method is called once command palette action was chosen for dispatching
|
||||
// We'll use this event to dispatch this command.
|
||||
// Arguments:
|
||||
// - command - command to dispatch
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_OnDispatchCommandRequested(const IInspectable& /*sender*/, const Microsoft::Terminal::Settings::Model::Command& command)
|
||||
{
|
||||
const auto& actionAndArgs = command.Action();
|
||||
_actionDispatch->DoAction(actionAndArgs);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This method is called once command palette command line was chosen for execution
|
||||
// We'll use this event to create a command line execution command and dispatch it.
|
||||
// Arguments:
|
||||
// - command - command to dispatch
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_OnCommandLineExecutionRequested(const IInspectable& /*sender*/, const winrt::hstring& commandLine)
|
||||
{
|
||||
ExecuteCommandlineArgs args{ commandLine };
|
||||
ActionAndArgs actionAndArgs{ ShortcutAction::ExecuteCommandline, args };
|
||||
_actionDispatch->DoAction(actionAndArgs);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This method is called once a tab was selected in tab switcher
|
||||
// We'll use this event to select the relevant tab
|
||||
// Arguments:
|
||||
// - tab - tab to select
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_OnSwitchToTabRequested(const IInspectable& /*sender*/, const winrt::TerminalApp::TabBase& tab)
|
||||
{
|
||||
uint32_t index{};
|
||||
if (_tabs.IndexOf(tab, index))
|
||||
{
|
||||
_SelectTab(index);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This method is called once on startup, on the first LayoutUpdated event.
|
||||
// We'll use this event to know that we have an ActualWidth and
|
||||
@@ -514,6 +561,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
page->_SplitPane(SplitState::Automatic,
|
||||
SplitType::Manual,
|
||||
0.5f,
|
||||
newTerminalArgs);
|
||||
}
|
||||
else
|
||||
@@ -554,7 +602,9 @@ namespace winrt::TerminalApp::implementation
|
||||
settingsItem.Click({ this, &TerminalPage::_SettingsButtonOnClick });
|
||||
newTabFlyout.Items().Append(settingsItem);
|
||||
|
||||
auto settingsKeyChord = keyBindings.GetKeyBindingForAction(ShortcutAction::OpenSettings);
|
||||
Microsoft::Terminal::Settings::Model::OpenSettingsArgs args{ SettingsTarget::SettingsFile };
|
||||
Microsoft::Terminal::Settings::Model::ActionAndArgs settingsAction{ ShortcutAction::OpenSettings, args };
|
||||
const auto settingsKeyChord{ keyBindings.GetKeyBindingForActionWithArgs(settingsAction) };
|
||||
if (settingsKeyChord)
|
||||
{
|
||||
_SetAcceleratorForMenuItem(settingsItem, settingsKeyChord);
|
||||
@@ -585,6 +635,21 @@ namespace winrt::TerminalApp::implementation
|
||||
newTabFlyout.Items().Append(aboutFlyout);
|
||||
}
|
||||
|
||||
// Before opening the fly-out set focus on the current tab
|
||||
// so no matter how fly-out is closed later on the focus will return to some tab.
|
||||
// We cannot do it on closing because if the window loses focus (alt+tab)
|
||||
// the closing event is not fired.
|
||||
// It is important to set the focus on the tab
|
||||
// Since the previous focus location might be discarded in the background,
|
||||
// e.g., the command palette will be dismissed by the menu,
|
||||
// and then closing the fly-out will move the focus to wrong location.
|
||||
newTabFlyout.Opening([this](auto&&, auto&&) {
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
{
|
||||
_tabs.GetAt(*index).Focus(FocusState::Programmatic);
|
||||
_UpdateMRUTab(index.value());
|
||||
}
|
||||
});
|
||||
_newTabButton.Flyout(newTabFlyout);
|
||||
}
|
||||
|
||||
@@ -679,11 +744,10 @@ namespace winrt::TerminalApp::implementation
|
||||
TermControl term{ settings, connection };
|
||||
|
||||
auto newTabImpl = winrt::make_self<TerminalTab>(profileGuid, term);
|
||||
_MakeSwitchToTabCommand(*newTabImpl, _tabs.Size());
|
||||
|
||||
// Add the new tab to the list of our tabs.
|
||||
_tabs.Append(*newTabImpl);
|
||||
_mruTabActions.Append(newTabImpl->SwitchToTabCommand());
|
||||
_mruTabs.Append(*newTabImpl);
|
||||
|
||||
newTabImpl->SetDispatch(*_actionDispatch);
|
||||
|
||||
@@ -749,7 +813,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TermControl newControl{ settings, debugConnection };
|
||||
_RegisterTerminalEvents(newControl, *newTabImpl);
|
||||
// Split (auto) with the debug tap.
|
||||
newTabImpl->SplitPane(SplitState::Automatic, profileGuid, newControl);
|
||||
newTabImpl->SplitPane(SplitState::Automatic, 0.5f, profileGuid, newControl);
|
||||
}
|
||||
|
||||
// This kicks off TabView::SelectionChanged, in response to which
|
||||
@@ -867,6 +931,34 @@ namespace winrt::TerminalApp::implementation
|
||||
_ShowAboutDialog();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// Called when the users pressed keyBindings while CommandPalette is open.
|
||||
// Arguments:
|
||||
// - e: the KeyRoutedEventArgs containing info about the keystroke.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_KeyDownHandler(Windows::Foundation::IInspectable const& /*sender*/, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e)
|
||||
{
|
||||
auto key = e.OriginalKey();
|
||||
auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down);
|
||||
auto const altDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down);
|
||||
auto const shiftDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down);
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalControl::KeyChord kc{ ctrlDown, altDown, shiftDown, static_cast<int32_t>(key) };
|
||||
auto setting = AppLogic::CurrentAppSettings();
|
||||
auto keymap = setting.GlobalSettings().KeyMap();
|
||||
const auto actionAndArgs = keymap.TryLookup(kc);
|
||||
if (actionAndArgs)
|
||||
{
|
||||
if (CommandPalette().Visibility() == Visibility::Visible && actionAndArgs.Action() != ShortcutAction::ToggleCommandPalette)
|
||||
{
|
||||
CommandPalette().Visibility(Visibility::Collapsed);
|
||||
}
|
||||
_actionDispatch->DoAction(actionAndArgs);
|
||||
e.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Configure the AppKeyBindings to use our ShortcutActionDispatch and the updated KeyMapping
|
||||
// as the object to handle dispatching ShortcutAction events.
|
||||
@@ -904,6 +996,8 @@ namespace winrt::TerminalApp::implementation
|
||||
_actionDispatch->TogglePaneZoom({ this, &TerminalPage::_HandleTogglePaneZoom });
|
||||
_actionDispatch->ScrollUpPage({ this, &TerminalPage::_HandleScrollUpPage });
|
||||
_actionDispatch->ScrollDownPage({ this, &TerminalPage::_HandleScrollDownPage });
|
||||
_actionDispatch->ScrollToTop({ this, &TerminalPage::_HandleScrollToTop });
|
||||
_actionDispatch->ScrollToBottom({ this, &TerminalPage::_HandleScrollToBottom });
|
||||
_actionDispatch->OpenSettings({ this, &TerminalPage::_HandleOpenSettings });
|
||||
_actionDispatch->PasteText({ this, &TerminalPage::_HandlePasteText });
|
||||
_actionDispatch->NewTab({ this, &TerminalPage::_HandleNewTab });
|
||||
@@ -914,7 +1008,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_actionDispatch->AdjustFontSize({ this, &TerminalPage::_HandleAdjustFontSize });
|
||||
_actionDispatch->Find({ this, &TerminalPage::_HandleFind });
|
||||
_actionDispatch->ResetFontSize({ this, &TerminalPage::_HandleResetFontSize });
|
||||
_actionDispatch->ToggleRetroEffect({ this, &TerminalPage::_HandleToggleRetroEffect });
|
||||
_actionDispatch->ToggleShaderEffects({ this, &TerminalPage::_HandleToggleShaderEffects });
|
||||
_actionDispatch->ToggleFocusMode({ this, &TerminalPage::_HandleToggleFocusMode });
|
||||
_actionDispatch->ToggleFullscreen({ this, &TerminalPage::_HandleToggleFullscreen });
|
||||
_actionDispatch->ToggleAlwaysOnTop({ this, &TerminalPage::_HandleToggleAlwaysOnTop });
|
||||
@@ -1003,34 +1097,31 @@ namespace winrt::TerminalApp::implementation
|
||||
// - Duplicates the current focused tab
|
||||
void TerminalPage::_DuplicateTabViewItem()
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(_tabs.GetAt(*index)))
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: GH#5047 - In the future, we should get the Profile of
|
||||
// the focused pane, and use that to build a new instance of the
|
||||
// settings so we can duplicate this tab/pane.
|
||||
//
|
||||
// Currently, if the profile doesn't exist anymore in our
|
||||
// settings, we'll silently do nothing.
|
||||
//
|
||||
// In the future, it will be preferable to just duplicate the
|
||||
// current control's settings, but we can't do that currently,
|
||||
// because we won't be able to create a new instance of the
|
||||
// connection without keeping an instance of the original Profile
|
||||
// object around.
|
||||
// TODO: GH#5047 - In the future, we should get the Profile of
|
||||
// the focused pane, and use that to build a new instance of the
|
||||
// settings so we can duplicate this tab/pane.
|
||||
//
|
||||
// Currently, if the profile doesn't exist anymore in our
|
||||
// settings, we'll silently do nothing.
|
||||
//
|
||||
// In the future, it will be preferable to just duplicate the
|
||||
// current control's settings, but we can't do that currently,
|
||||
// because we won't be able to create a new instance of the
|
||||
// connection without keeping an instance of the original Profile
|
||||
// object around.
|
||||
|
||||
const auto& profileGuid = terminalTab->GetFocusedProfile();
|
||||
if (profileGuid.has_value())
|
||||
{
|
||||
const auto settings{ winrt::make<TerminalSettings>(_settings, profileGuid.value(), *_bindings) };
|
||||
_CreateNewTabFromSettings(profileGuid.value(), settings);
|
||||
}
|
||||
const auto& profileGuid = terminalTab->GetFocusedProfile();
|
||||
if (profileGuid.has_value())
|
||||
{
|
||||
const auto settings{ winrt::make<TerminalSettings>(_settings, profileGuid.value(), *_bindings) };
|
||||
_CreateNewTabFromSettings(profileGuid.value(), settings);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1055,73 +1146,78 @@ namespace winrt::TerminalApp::implementation
|
||||
// - tabIndex: the index of the tab to be removed
|
||||
void TerminalPage::_RemoveTabViewItemByIndex(uint32_t tabIndex)
|
||||
{
|
||||
// We use _removing flag to suppress _OnTabSelectionChanged events
|
||||
// that might get triggered while removing
|
||||
_removing = true;
|
||||
auto unsetRemoving = wil::scope_exit([&]() noexcept { _removing = false; });
|
||||
|
||||
const auto focusedTabIndex{ _GetFocusedTabIndex() };
|
||||
|
||||
// Removing the tab from the collection should destroy its control and disconnect its connection,
|
||||
// but it doesn't always do so. The UI tree may still be holding the control and preventing its destruction.
|
||||
auto tab{ _tabs.GetAt(tabIndex) };
|
||||
tab.Shutdown();
|
||||
|
||||
uint32_t mruIndex;
|
||||
if (_mruTabActions.IndexOf(_tabs.GetAt(tabIndex).SwitchToTabCommand(), mruIndex))
|
||||
if (_mruTabs.IndexOf(_tabs.GetAt(tabIndex), mruIndex))
|
||||
{
|
||||
_mruTabActions.RemoveAt(mruIndex);
|
||||
_mruTabs.RemoveAt(mruIndex);
|
||||
}
|
||||
|
||||
_tabs.RemoveAt(tabIndex);
|
||||
_tabView.TabItems().RemoveAt(tabIndex);
|
||||
_UpdateTabIndices();
|
||||
|
||||
// If the tab switcher is currently open, update it to reflect the
|
||||
// current list of tabs.
|
||||
const auto tabSwitchMode = _settings.GlobalSettings().TabSwitcherMode();
|
||||
const bool commandPaletteIsVisible = CommandPalette().Visibility() == Visibility::Visible;
|
||||
if (tabSwitchMode == TabSwitcherMode::MostRecentlyUsed && commandPaletteIsVisible)
|
||||
{
|
||||
CommandPalette().SetTabActions(_mruTabActions, false);
|
||||
}
|
||||
else if (commandPaletteIsVisible)
|
||||
{
|
||||
_UpdatePaletteWithInOrderTabs();
|
||||
}
|
||||
|
||||
// To close the window here, we need to close the hosting window.
|
||||
if (_tabs.Size() == 0)
|
||||
{
|
||||
_lastTabClosedHandlers(*this, nullptr);
|
||||
}
|
||||
else if (_isFullscreen || _rearranging)
|
||||
else if (focusedTabIndex.has_value() && focusedTabIndex.value() == gsl::narrow_cast<uint32_t>(tabIndex))
|
||||
{
|
||||
// GH#5799 - If we're fullscreen, the TabView isn't visible. If it's
|
||||
// not Visible, it's _not_ going to raise a SelectionChanged event,
|
||||
// which is what we usually use to focus another tab. Instead, we'll
|
||||
// have to do it manually here.
|
||||
//
|
||||
// GH#5559 Similarly, we suppress _OnTabItemsChanged events during a
|
||||
// rearrange, so if a tab is closed while we're rearranging tabs, do
|
||||
// this manually.
|
||||
//
|
||||
// We can't use
|
||||
// auto selectedIndex = _tabView.SelectedIndex();
|
||||
// Because this will always return -1 in this scenario unfortunately.
|
||||
//
|
||||
// So, what we're going to try to do is move the focus to the tab
|
||||
// to the left, within the bounds of how many tabs we have.
|
||||
//
|
||||
// EX: we have 4 tabs: [A, B, C, D]. If we close:
|
||||
// * A (tabIndex=0): We'll want to focus tab B (now in index 0)
|
||||
// * B (tabIndex=1): We'll want to focus tab A (now in index 0)
|
||||
// * C (tabIndex=2): We'll want to focus tab B (now in index 1)
|
||||
// * D (tabIndex=3): We'll want to focus tab C (now in index 2)
|
||||
const auto newSelectedIndex = std::clamp<int32_t>(tabIndex - 1, 0, _tabs.Size());
|
||||
// _UpdatedSelectedTab will do the work of setting up the new tab as
|
||||
// the focused one, and unfocusing all the others.
|
||||
_UpdatedSelectedTab(newSelectedIndex);
|
||||
// Manually select the new tab to get focus, rather than relying on TabView since:
|
||||
// 1. We want to customize this behavior (e.g., use MRU logic)
|
||||
// 2. In fullscreen (GH#5799) and focus (GH#7916) modes the _OnTabItemsChanged is not fired
|
||||
// 3. When rearranging tabs (GH#7916) _OnTabItemsChanged is suppressed
|
||||
const auto tabSwitchMode = _settings.GlobalSettings().TabSwitcherMode();
|
||||
|
||||
// Also, we need to _manually_ set the SelectedItem of the tabView
|
||||
// here. If we don't, then the TabView will technically not have a
|
||||
// selected item at all, which can make things like ClosePane not
|
||||
// work correctly.
|
||||
auto newSelectedTab{ _tabs.GetAt(newSelectedIndex) };
|
||||
_tabView.SelectedItem(newSelectedTab.TabViewItem());
|
||||
if (tabSwitchMode == TabSwitcherMode::MostRecentlyUsed)
|
||||
{
|
||||
const auto newSelectedTab = _mruTabs.GetAt(0);
|
||||
|
||||
uint32_t newSelectedIndex;
|
||||
if (_tabs.IndexOf(newSelectedTab, newSelectedIndex))
|
||||
{
|
||||
_UpdatedSelectedTab(newSelectedIndex);
|
||||
_tabView.SelectedItem(newSelectedTab.TabViewItem());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We can't use
|
||||
// auto selectedIndex = _tabView.SelectedIndex();
|
||||
// Because this will always return -1 in this scenario unfortunately.
|
||||
//
|
||||
// So, what we're going to try to do is move the focus to the tab
|
||||
// to the left, within the bounds of how many tabs we have.
|
||||
//
|
||||
// EX: we have 4 tabs: [A, B, C, D]. If we close:
|
||||
// * A (tabIndex=0): We'll want to focus tab B (now in index 0)
|
||||
// * B (tabIndex=1): We'll want to focus tab A (now in index 0)
|
||||
// * C (tabIndex=2): We'll want to focus tab B (now in index 1)
|
||||
// * D (tabIndex=3): We'll want to focus tab C (now in index 2)
|
||||
const auto newSelectedIndex = std::clamp<int32_t>(tabIndex - 1, 0, _tabs.Size());
|
||||
// _UpdatedSelectedTab will do the work of setting up the new tab as
|
||||
// the focused one, and unfocusing all the others.
|
||||
_UpdatedSelectedTab(newSelectedIndex);
|
||||
|
||||
// Also, we need to _manually_ set the SelectedItem of the tabView
|
||||
// here. If we don't, then the TabView will technically not have a
|
||||
// selected item at all, which can make things like ClosePane not
|
||||
// work correctly.
|
||||
auto newSelectedTab{ _tabs.GetAt(newSelectedIndex) };
|
||||
_tabView.SelectedItem(newSelectedTab.TabViewItem());
|
||||
}
|
||||
}
|
||||
|
||||
// GH#5559 - If we were in the middle of a drag/drop, end it by clearing
|
||||
@@ -1218,19 +1314,6 @@ namespace winrt::TerminalApp::implementation
|
||||
// _ClearNewTabButtonColor();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Updates the command palette (tab switcher) with a list of actions
|
||||
// reflecting the current in-order list of tabs.
|
||||
void TerminalPage::_UpdatePaletteWithInOrderTabs()
|
||||
{
|
||||
auto tabCommands = winrt::single_threaded_vector<Command>();
|
||||
for (const auto& tab : _tabs)
|
||||
{
|
||||
tabCommands.Append(tab.SwitchToTabCommand());
|
||||
}
|
||||
CommandPalette().SetTabActions(tabCommands, true);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets focus to the tab to the right or left the currently selected tab.
|
||||
void TerminalPage::_SelectNextTab(const bool bMoveRight)
|
||||
@@ -1268,7 +1351,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// In this case, our focused tab index (in the MRU ordering) is
|
||||
// always 0. So, going next should go to index 1, and going prev
|
||||
// should wrap to the end.
|
||||
uint32_t tabCount = _mruTabActions.Size();
|
||||
uint32_t tabCount = _mruTabs.Size();
|
||||
newTabIndex = ((tabCount + (bMoveRight ? 1 : -1)) % tabCount);
|
||||
}
|
||||
|
||||
@@ -1276,16 +1359,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (useTabSwitcher)
|
||||
{
|
||||
if (useInOrderTabIndex)
|
||||
{
|
||||
// Set up the list of in-order tabs
|
||||
_UpdatePaletteWithInOrderTabs();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set up the list of MRU tabs
|
||||
CommandPalette().SetTabActions(_mruTabActions, true);
|
||||
}
|
||||
CommandPalette().SetTabs(useInOrderTabIndex ? _tabs : _mruTabs, true);
|
||||
|
||||
// Otherwise, set up the tab switcher in the selected mode, with
|
||||
// the given ordering, and make it visible.
|
||||
@@ -1343,20 +1417,17 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void TerminalPage::_UnZoomIfNeeded()
|
||||
{
|
||||
if (auto focusedTab = _GetFocusedTab())
|
||||
if (const auto activeTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto activeTab = _GetTerminalTabImpl(focusedTab))
|
||||
if (activeTab->IsZoomed())
|
||||
{
|
||||
if (activeTab->IsZoomed())
|
||||
{
|
||||
// Remove the content from the tab first, so Pane::UnZoom can
|
||||
// re-attach the content to the tree w/in the pane
|
||||
_tabContent.Children().Clear();
|
||||
// In ExitZoom, we'll change the Tab's Content(), triggering the
|
||||
// content changed event, which will re-attach the tab's new content
|
||||
// root to the tree.
|
||||
activeTab->ExitZoom();
|
||||
}
|
||||
// Remove the content from the tab first, so Pane::UnZoom can
|
||||
// re-attach the content to the tree w/in the pane
|
||||
_tabContent.Children().Clear();
|
||||
// In ExitZoom, we'll change the Tab's Content(), triggering the
|
||||
// content changed event, which will re-attach the tab's new content
|
||||
// root to the tree.
|
||||
activeTab->ExitZoom();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1369,26 +1440,20 @@ namespace winrt::TerminalApp::implementation
|
||||
// - direction: The direction to move the focus in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_MoveFocus(const Direction& direction)
|
||||
void TerminalPage::_MoveFocus(const FocusDirection& direction)
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(_tabs.GetAt(*index)))
|
||||
{
|
||||
_UnZoomIfNeeded();
|
||||
terminalTab->NavigateFocus(direction);
|
||||
}
|
||||
_UnZoomIfNeeded();
|
||||
terminalTab->NavigateFocus(direction);
|
||||
}
|
||||
}
|
||||
|
||||
TermControl TerminalPage::_GetActiveControl()
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(_tabs.GetAt(*index)))
|
||||
{
|
||||
return terminalTab->GetActiveTerminalControl();
|
||||
}
|
||||
return terminalTab->GetActiveTerminalControl();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1413,7 +1478,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// Method Description:
|
||||
// - returns a com_ptr to the currently focused tab. This might return null,
|
||||
// so make sure to check the result!
|
||||
winrt::TerminalApp::TabBase TerminalPage::_GetFocusedTab()
|
||||
winrt::TerminalApp::TabBase TerminalPage::_GetFocusedTab() const noexcept
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
{
|
||||
@@ -1422,6 +1487,18 @@ namespace winrt::TerminalApp::implementation
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - returns a com_ptr to the currently focused tab implementation. This might return null,
|
||||
// so make sure to check the result!
|
||||
winrt::com_ptr<TerminalTab> TerminalPage::_GetFocusedTabImpl() const noexcept
|
||||
{
|
||||
if (auto tab{ _GetFocusedTab() })
|
||||
{
|
||||
return _GetTerminalTabImpl(tab);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - An async method for changing the focused tab on the UI thread. This
|
||||
// method will _only_ set the selected item of the TabView, which will
|
||||
@@ -1463,13 +1540,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// tab's Closed event.
|
||||
void TerminalPage::_CloseFocusedPane()
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(_tabs.GetAt(*index)))
|
||||
{
|
||||
_UnZoomIfNeeded();
|
||||
terminalTab->ClosePane();
|
||||
}
|
||||
_UnZoomIfNeeded();
|
||||
terminalTab->ClosePane();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1512,26 +1586,23 @@ namespace winrt::TerminalApp::implementation
|
||||
// - rowsToScroll: a number of lines to move the viewport. If not provided we will use a system default.
|
||||
void TerminalPage::_Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll)
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(_tabs.GetAt(*index)))
|
||||
uint32_t realRowsToScroll;
|
||||
if (rowsToScroll == nullptr)
|
||||
{
|
||||
uint32_t realRowsToScroll;
|
||||
if (rowsToScroll == nullptr)
|
||||
{
|
||||
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
|
||||
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
|
||||
terminalTab->GetActiveTerminalControl().GetViewHeight() :
|
||||
_systemRowsToScroll;
|
||||
}
|
||||
else
|
||||
{
|
||||
// use the custom value specified in the command
|
||||
realRowsToScroll = rowsToScroll.Value();
|
||||
}
|
||||
auto scrollDelta = _ComputeScrollDelta(scrollDirection, realRowsToScroll);
|
||||
terminalTab->Scroll(scrollDelta);
|
||||
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
|
||||
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
|
||||
terminalTab->GetActiveTerminalControl().GetViewHeight() :
|
||||
_systemRowsToScroll;
|
||||
}
|
||||
else
|
||||
{
|
||||
// use the custom value specified in the command
|
||||
realRowsToScroll = rowsToScroll.Value();
|
||||
}
|
||||
auto scrollDelta = _ComputeScrollDelta(scrollDirection, realRowsToScroll);
|
||||
terminalTab->Scroll(scrollDelta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1548,6 +1619,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// configurations. See CascadiaSettings::BuildSettings for more details.
|
||||
void TerminalPage::_SplitPane(const SplitState splitType,
|
||||
const SplitType splitMode,
|
||||
const float splitSize,
|
||||
const NewTerminalArgs& newTerminalArgs)
|
||||
{
|
||||
// Do nothing if we're requesting no split.
|
||||
@@ -1556,17 +1628,9 @@ namespace winrt::TerminalApp::implementation
|
||||
return;
|
||||
}
|
||||
|
||||
auto indexOpt = _GetFocusedTabIndex();
|
||||
const auto focusedTab{ _GetFocusedTabImpl() };
|
||||
|
||||
// Do nothing if for some reason, there's no tab in focus. We don't want to crash.
|
||||
if (!indexOpt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto focusedTab = _GetTerminalTabImpl(_tabs.GetAt(*indexOpt));
|
||||
|
||||
// Do nothing if the focused tab isn't a TerminalTab
|
||||
// Do nothing if no TerminalTab is focused
|
||||
if (!focusedTab)
|
||||
{
|
||||
return;
|
||||
@@ -1617,7 +1681,7 @@ namespace winrt::TerminalApp::implementation
|
||||
realSplitType = focusedTab->PreCalculateAutoSplit(availableSpace);
|
||||
}
|
||||
|
||||
const auto canSplit = focusedTab->PreCalculateCanSplit(realSplitType, availableSpace);
|
||||
const auto canSplit = focusedTab->PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
|
||||
if (!canSplit)
|
||||
{
|
||||
return;
|
||||
@@ -1630,7 +1694,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
_UnZoomIfNeeded();
|
||||
|
||||
focusedTab->SplitPane(realSplitType, realGuid, newControl);
|
||||
focusedTab->SplitPane(realSplitType, splitSize, realGuid, newControl);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
@@ -1643,15 +1707,12 @@ namespace winrt::TerminalApp::implementation
|
||||
// - direction: The direction to move the separator in.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_ResizePane(const Direction& direction)
|
||||
void TerminalPage::_ResizePane(const ResizeDirection& direction)
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(_tabs.GetAt(*index)))
|
||||
{
|
||||
_UnZoomIfNeeded();
|
||||
terminalTab->ResizePane(direction);
|
||||
}
|
||||
_UnZoomIfNeeded();
|
||||
terminalTab->ResizePane(direction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1662,14 +1723,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// - scrollDirection: ScrollUp will move the viewport up, ScrollDown will move the viewport down
|
||||
void TerminalPage::_ScrollPage(ScrollDirection scrollDirection)
|
||||
{
|
||||
auto indexOpt = _GetFocusedTabIndex();
|
||||
// Do nothing if for some reason, there's no tab in focus. We don't want to crash.
|
||||
if (!indexOpt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto terminalTab = _GetTerminalTabImpl(_tabs.GetAt(*indexOpt)))
|
||||
// Do nothing if for some reason, there's no terminal tab in focus. We don't want to crash.
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
const auto control = _GetActiveControl();
|
||||
const auto termHeight = control.GetViewHeight();
|
||||
@@ -1678,6 +1733,15 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_ScrollToBufferEdge(ScrollDirection scrollDirection)
|
||||
{
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
auto scrollDelta = _ComputeScrollDelta(scrollDirection, INT_MAX);
|
||||
terminalTab->Scroll(scrollDelta);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the title of the currently focused terminal control. If there
|
||||
// isn't a control selected for any reason, returns "Windows Terminal"
|
||||
@@ -1784,12 +1848,9 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (_settings && _settings.GlobalSettings().SnapToGridOnResize())
|
||||
{
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
if (const auto terminalTab{ _GetFocusedTabImpl() })
|
||||
{
|
||||
if (auto terminalTab = _GetTerminalTabImpl(_tabs.GetAt(*index)))
|
||||
{
|
||||
return terminalTab->CalcSnappedDimension(widthOrHeight, dimension);
|
||||
}
|
||||
return terminalTab->CalcSnappedDimension(widthOrHeight, dimension);
|
||||
}
|
||||
}
|
||||
return dimension;
|
||||
@@ -2039,32 +2100,39 @@ namespace winrt::TerminalApp::implementation
|
||||
// a background thread, as to not hang/crash the UI thread.
|
||||
fire_and_forget TerminalPage::_LaunchSettings(const SettingsTarget target)
|
||||
{
|
||||
// This will switch the execution of the function to a background (not
|
||||
// UI) thread. This is IMPORTANT, because the Windows.Storage API's
|
||||
// (used for retrieving the path to the file) will crash on the UI
|
||||
// thread, because the main thread is a STA.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
auto openFile = [](const auto& filePath) {
|
||||
HINSTANCE res = ShellExecute(nullptr, nullptr, filePath.c_str(), nullptr, nullptr, SW_SHOW);
|
||||
if (static_cast<int>(reinterpret_cast<uintptr_t>(res)) <= 32)
|
||||
{
|
||||
ShellExecute(nullptr, nullptr, L"notepad", filePath.c_str(), nullptr, SW_SHOW);
|
||||
}
|
||||
};
|
||||
|
||||
switch (target)
|
||||
if (target == SettingsTarget::SettingsUI)
|
||||
{
|
||||
case SettingsTarget::DefaultsFile:
|
||||
openFile(CascadiaSettings::DefaultSettingsPath());
|
||||
break;
|
||||
case SettingsTarget::SettingsFile:
|
||||
openFile(CascadiaSettings::SettingsPath());
|
||||
break;
|
||||
case SettingsTarget::AllFiles:
|
||||
openFile(CascadiaSettings::DefaultSettingsPath());
|
||||
openFile(CascadiaSettings::SettingsPath());
|
||||
break;
|
||||
_OpenSettingsUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This will switch the execution of the function to a background (not
|
||||
// UI) thread. This is IMPORTANT, because the Windows.Storage API's
|
||||
// (used for retrieving the path to the file) will crash on the UI
|
||||
// thread, because the main thread is a STA.
|
||||
co_await winrt::resume_background();
|
||||
|
||||
auto openFile = [](const auto& filePath) {
|
||||
HINSTANCE res = ShellExecute(nullptr, nullptr, filePath.c_str(), nullptr, nullptr, SW_SHOW);
|
||||
if (static_cast<int>(reinterpret_cast<uintptr_t>(res)) <= 32)
|
||||
{
|
||||
ShellExecute(nullptr, nullptr, L"notepad", filePath.c_str(), nullptr, SW_SHOW);
|
||||
}
|
||||
};
|
||||
|
||||
switch (target)
|
||||
{
|
||||
case SettingsTarget::DefaultsFile:
|
||||
openFile(CascadiaSettings::DefaultSettingsPath());
|
||||
break;
|
||||
case SettingsTarget::SettingsFile:
|
||||
openFile(CascadiaSettings::SettingsPath());
|
||||
break;
|
||||
case SettingsTarget::AllFiles:
|
||||
openFile(CascadiaSettings::DefaultSettingsPath());
|
||||
openFile(CascadiaSettings::SettingsPath());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2093,6 +2161,7 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
CommandPalette().Visibility(Visibility::Collapsed);
|
||||
_UpdateTabView();
|
||||
}
|
||||
|
||||
@@ -2162,7 +2231,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - eventArgs: the event's constituent arguments
|
||||
void TerminalPage::_OnTabSelectionChanged(const IInspectable& sender, const WUX::Controls::SelectionChangedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
if (!_rearranging)
|
||||
if (!_rearranging && !_removing)
|
||||
{
|
||||
auto tabView = sender.as<MUX::Controls::TabView>();
|
||||
auto selectedIndex = tabView.SelectedIndex();
|
||||
@@ -2255,6 +2324,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// Force the TerminalTab to re-grab its currently active control's title.
|
||||
terminalTab->UpdateTitle();
|
||||
}
|
||||
else if (auto settingsTab = tab.try_as<TerminalApp::SettingsTab>())
|
||||
{
|
||||
settingsTab.UpdateSettings(_settings);
|
||||
}
|
||||
}
|
||||
|
||||
auto weakThis{ get_weak() };
|
||||
@@ -2644,46 +2717,28 @@ namespace winrt::TerminalApp::implementation
|
||||
// - an empty list if we failed to parse, otherwise a list of actions to execute.
|
||||
std::vector<ActionAndArgs> TerminalPage::ConvertExecuteCommandlineToActions(const ExecuteCommandlineArgs& args)
|
||||
{
|
||||
if (!args || args.Commandline().empty())
|
||||
::TerminalApp::AppCommandlineArgs appArgs;
|
||||
if (appArgs.ParseArgs(args) == 0)
|
||||
{
|
||||
return {};
|
||||
return appArgs.GetStartupActions();
|
||||
}
|
||||
// Convert the commandline into an array of args with
|
||||
// CommandLineToArgvW, similar to how the app typically does when
|
||||
// called from the commandline.
|
||||
int argc = 0;
|
||||
wil::unique_any<LPWSTR*, decltype(&::LocalFree), ::LocalFree> argv{ CommandLineToArgvW(args.Commandline().c_str(), &argc) };
|
||||
if (argv)
|
||||
{
|
||||
std::vector<winrt::hstring> args;
|
||||
|
||||
// Make sure the first argument is wt.exe, because ParseArgs will
|
||||
// always skip the program name. The particular value of this first
|
||||
// string doesn't terribly matter.
|
||||
args.emplace_back(L"wt.exe");
|
||||
for (auto& elem : wil::make_range(argv.get(), argc))
|
||||
{
|
||||
args.emplace_back(elem);
|
||||
}
|
||||
winrt::array_view<const winrt::hstring> argsView{ args };
|
||||
|
||||
::TerminalApp::AppCommandlineArgs appArgs;
|
||||
if (appArgs.ParseArgs(argsView) == 0)
|
||||
{
|
||||
return appArgs.GetStartupActions();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void TerminalPage::_CommandPaletteClosed(const IInspectable& /*sender*/,
|
||||
const RoutedEventArgs& /*eventArgs*/)
|
||||
{
|
||||
// Return focus to the active control
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
// We don't want to set focus on the tab if fly-out is open as it will be closed
|
||||
// TODO GH#5400: consider checking we are not in the opening state, by hooking both Opening and Open events
|
||||
if (!_newTabButton.Flyout().IsOpen())
|
||||
{
|
||||
_tabs.GetAt(*index).Focus(FocusState::Programmatic);
|
||||
_UpdateMRUTab(index.value());
|
||||
// Return focus to the active control
|
||||
if (auto index{ _GetFocusedTabIndex() })
|
||||
{
|
||||
_tabs.GetAt(*index).Focus(FocusState::Programmatic);
|
||||
_UpdateMRUTab(index.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2727,6 +2782,72 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates a settings UI tab and focuses it. If there's already a settings UI tab open,
|
||||
// just focus the existing one.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_OpenSettingsUI()
|
||||
{
|
||||
// If we're holding the settings tab's switch command, don't create a new one, switch to the existing one.
|
||||
if (!_settingsTab)
|
||||
{
|
||||
winrt::Microsoft::Terminal::Settings::Editor::MainPage sui{ _settings };
|
||||
if (_hostingHwnd)
|
||||
{
|
||||
sui.SetHostingWindow(reinterpret_cast<uint64_t>(*_hostingHwnd));
|
||||
}
|
||||
|
||||
sui.OpenJson([weakThis{ get_weak() }](auto&& /*s*/, winrt::Microsoft::Terminal::Settings::Model::SettingsTarget e) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
page->_LaunchSettings(e);
|
||||
}
|
||||
});
|
||||
|
||||
auto newTabImpl = winrt::make_self<SettingsTab>(sui);
|
||||
|
||||
// Add the new tab to the list of our tabs.
|
||||
_tabs.Append(*newTabImpl);
|
||||
_mruTabs.Append(*newTabImpl);
|
||||
|
||||
newTabImpl->SetDispatch(*_actionDispatch);
|
||||
|
||||
// Give the tab its index in the _tabs vector so it can manage its own SwitchToTab command.
|
||||
_UpdateTabIndices();
|
||||
|
||||
// Don't capture a strong ref to the tab. If the tab is removed as this
|
||||
// is called, we don't really care anymore about handling the event.
|
||||
auto weakTab = make_weak(newTabImpl);
|
||||
|
||||
auto tabViewItem = newTabImpl->TabViewItem();
|
||||
_tabView.TabItems().Append(tabViewItem);
|
||||
|
||||
tabViewItem.PointerPressed({ this, &TerminalPage::_OnTabClick });
|
||||
|
||||
// When the tab is closed, remove it from our list of tabs.
|
||||
newTabImpl->Closed([tabViewItem, weakThis{ get_weak() }](auto&& /*s*/, auto&& /*e*/) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
page->_settingsTab = nullptr;
|
||||
page->_RemoveOnCloseRoutine(tabViewItem, page);
|
||||
}
|
||||
});
|
||||
|
||||
_settingsTab = *newTabImpl;
|
||||
|
||||
// This kicks off TabView::SelectionChanged, in response to which
|
||||
// we'll attach the terminal's Xaml control to the Xaml root.
|
||||
_tabView.SelectedItem(tabViewItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tabView.SelectedItem(_settingsTab.TabViewItem());
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns a com_ptr to the implementation type of the given tab if it's a TerminalTab.
|
||||
// If the tab is not a TerminalTab, returns nullptr.
|
||||
@@ -2735,7 +2856,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// Return Value:
|
||||
// - If the tab is a TerminalTab, a com_ptr to the implementation type.
|
||||
// If the tab is not a TerminalTab, nullptr
|
||||
winrt::com_ptr<TerminalTab> TerminalPage::_GetTerminalTabImpl(const TerminalApp::TabBase& tab) const
|
||||
winrt::com_ptr<TerminalTab> TerminalPage::_GetTerminalTabImpl(const TerminalApp::TabBase& tab)
|
||||
{
|
||||
if (auto terminalTab = tab.try_as<TerminalApp::TerminalTab>())
|
||||
{
|
||||
@@ -2750,27 +2871,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Initializes a SwitchToTab command object for this Tab instance.
|
||||
// This should be done before the tab is added to the _tabs vector so that
|
||||
// controls like the CmdPal that observe the vector changes can always expect
|
||||
// a SwitchToTab command to be available.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_MakeSwitchToTabCommand(const TerminalApp::TabBase& tab, const uint32_t index)
|
||||
{
|
||||
SwitchToTabArgs args{ index };
|
||||
ActionAndArgs focusTabAction{ ShortcutAction::SwitchToTab, args };
|
||||
|
||||
Command command;
|
||||
command.Action(focusTabAction);
|
||||
command.Name(tab.Title());
|
||||
command.Icon(tab.Icon());
|
||||
|
||||
tab.SwitchToTabCommand(command);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Computes the delta for scrolling the tab's viewport.
|
||||
// Arguments:
|
||||
@@ -2813,22 +2913,13 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_UpdateMRUTab(const uint32_t index)
|
||||
{
|
||||
uint32_t mruIndex;
|
||||
auto command = _tabs.GetAt(index).SwitchToTabCommand();
|
||||
if (_mruTabActions.IndexOf(command, mruIndex))
|
||||
const auto tab = _tabs.GetAt(index);
|
||||
if (_mruTabs.IndexOf(tab, mruIndex))
|
||||
{
|
||||
if (mruIndex > 0)
|
||||
{
|
||||
_mruTabActions.RemoveAt(mruIndex);
|
||||
_mruTabActions.InsertAt(0, command);
|
||||
|
||||
// If the tab switcher is currently open, AND we're using it in
|
||||
// MRU mode, then update it to reflect the current list of tabs.
|
||||
const auto tabSwitchMode = _settings.GlobalSettings().TabSwitcherMode();
|
||||
const bool commandPaletteIsVisible = CommandPalette().Visibility() == Visibility::Visible;
|
||||
if (tabSwitchMode == TabSwitcherMode::MostRecentlyUsed && commandPaletteIsVisible)
|
||||
{
|
||||
CommandPalette().SetTabActions(_mruTabActions, false);
|
||||
}
|
||||
_mruTabs.RemoveAt(mruIndex);
|
||||
_mruTabs.InsertAt(0, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2862,9 +2953,9 @@ namespace winrt::TerminalApp::implementation
|
||||
// Service" is disabled.
|
||||
void TerminalPage::ShowKeyboardServiceWarning()
|
||||
{
|
||||
if (auto presenter{ _dialogPresenter.get() })
|
||||
if (auto keyboardWarningInfoBar = FindName(L"KeyboardWarningInfoBar").try_as<MUX::Controls::InfoBar>())
|
||||
{
|
||||
presenter.ShowDialog(FindName(L"KeyboardServiceDisabledDialog").try_as<WUX::Controls::ContentDialog>());
|
||||
keyboardWarningInfoBar.IsOpen(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2913,9 +3004,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Method Description:
|
||||
// - Return the fully-formed warning message for the
|
||||
// "KeyboardServiceDisabled" dialog. This dialog is used to warn the user
|
||||
// "KeyboardServiceDisabled" InfoBar. This InfoBar is used to warn the user
|
||||
// if the keyboard service is disabled, and uses the OS localization for
|
||||
// the service's actual name. It's bound to the dialog in XAML.
|
||||
// the service's actual name. It's bound to the bar in XAML.
|
||||
// Return Value:
|
||||
// - The warning message, including the OS-localized service name.
|
||||
winrt::hstring TerminalPage::KeyboardServiceDisabledText()
|
||||
|
||||
@@ -110,11 +110,13 @@ namespace winrt::TerminalApp::implementation
|
||||
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<TerminalApp::TabBase> _tabs;
|
||||
Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::Command> _mruTabActions;
|
||||
winrt::com_ptr<TerminalTab> _GetTerminalTabImpl(const TerminalApp::TabBase& tab) const;
|
||||
Windows::Foundation::Collections::IVector<TerminalApp::TabBase> _mruTabs;
|
||||
static winrt::com_ptr<TerminalTab> _GetTerminalTabImpl(const TerminalApp::TabBase& tab);
|
||||
|
||||
void _UpdateTabIndices();
|
||||
|
||||
TerminalApp::SettingsTab _settingsTab{ nullptr };
|
||||
|
||||
bool _isInFocusMode{ false };
|
||||
bool _isFullscreen{ false };
|
||||
bool _isAlwaysOnTop{ false };
|
||||
@@ -122,6 +124,7 @@ namespace winrt::TerminalApp::implementation
|
||||
bool _rearranging;
|
||||
std::optional<int> _rearrangeFrom;
|
||||
std::optional<int> _rearrangeTo;
|
||||
bool _removing{ false };
|
||||
|
||||
uint32_t _systemRowsToScroll{ DefaultRowsToScroll };
|
||||
|
||||
@@ -154,6 +157,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void _AboutButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
void _ThirdPartyNoticesOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
||||
|
||||
void _KeyDownHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
|
||||
void _HookupKeyBindings(const Microsoft::Terminal::Settings::Model::KeyMapping& keymap) noexcept;
|
||||
void _RegisterActionCallbacks();
|
||||
|
||||
@@ -162,7 +166,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void _UpdateTabView();
|
||||
void _UpdateTabWidthMode();
|
||||
void _UpdateCommandsForPalette();
|
||||
void _UpdatePaletteWithInOrderTabs();
|
||||
|
||||
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, Microsoft::Terminal::Settings::Model::Command> _ExpandCommands(Windows::Foundation::Collections::IMapView<winrt::hstring, Microsoft::Terminal::Settings::Model::Command> commandsToExpand,
|
||||
Windows::Foundation::Collections::IVectorView<Microsoft::Terminal::Settings::Model::Profile> profiles,
|
||||
Windows::Foundation::Collections::IMapView<winrt::hstring, Microsoft::Terminal::Settings::Model::ColorScheme> schemes);
|
||||
@@ -175,11 +179,13 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _SelectNextTab(const bool bMoveRight);
|
||||
bool _SelectTab(const uint32_t tabIndex);
|
||||
void _MoveFocus(const Microsoft::Terminal::Settings::Model::Direction& direction);
|
||||
void _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
|
||||
|
||||
winrt::Microsoft::Terminal::TerminalControl::TermControl _GetActiveControl();
|
||||
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
|
||||
TerminalApp::TabBase _GetFocusedTab();
|
||||
TerminalApp::TabBase _GetFocusedTab() const noexcept;
|
||||
winrt::com_ptr<TerminalTab> _GetFocusedTabImpl() const noexcept;
|
||||
|
||||
winrt::fire_and_forget _SetFocusedTabIndex(const uint32_t tabIndex);
|
||||
void _CloseFocusedTab();
|
||||
void _CloseFocusedPane();
|
||||
@@ -190,9 +196,15 @@ namespace winrt::TerminalApp::implementation
|
||||
// Todo: add more event implementations here
|
||||
// MSFT:20641986: Add keybindings for New Window
|
||||
void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll);
|
||||
void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitState splitType, const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
|
||||
void _ResizePane(const Microsoft::Terminal::Settings::Model::Direction& direction);
|
||||
|
||||
void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitState splitType,
|
||||
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual,
|
||||
const float splitSize = 0.5f,
|
||||
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
|
||||
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
|
||||
|
||||
void _ScrollPage(ScrollDirection scrollDirection);
|
||||
void _ScrollToBufferEdge(ScrollDirection scrollDirection);
|
||||
void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::TerminalControl::KeyChord& keyChord);
|
||||
|
||||
winrt::fire_and_forget _CopyToClipboardHandler(const IInspectable sender, const winrt::Microsoft::Terminal::TerminalControl::CopyToClipboardEventArgs copiedData);
|
||||
@@ -220,6 +232,10 @@ namespace winrt::TerminalApp::implementation
|
||||
void _OnFirstLayout(const IInspectable& sender, const IInspectable& eventArgs);
|
||||
void _UpdatedSelectedTab(const int32_t index);
|
||||
|
||||
void _OnDispatchCommandRequested(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::Command& command);
|
||||
void _OnCommandLineExecutionRequested(const IInspectable& sender, const winrt::hstring& commandLine);
|
||||
void _OnSwitchToTabRequested(const IInspectable& sender, const winrt::TerminalApp::TabBase& tab);
|
||||
|
||||
void _Find();
|
||||
|
||||
winrt::fire_and_forget _RefreshUIForSettingsReload();
|
||||
@@ -237,12 +253,9 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _OpenSettingsUI();
|
||||
|
||||
void _MakeSwitchToTabCommand(const TerminalApp::TabBase& tab, const uint32_t index);
|
||||
|
||||
static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll);
|
||||
static uint32_t _ReadSystemRowsToScroll();
|
||||
|
||||
void _UpdateTabSwitcherCommands(const bool mru);
|
||||
void _UpdateMRUTab(const uint32_t index);
|
||||
|
||||
void _TryMoveTab(const uint32_t currentTabIndex, const int32_t suggestedNewTabIndex);
|
||||
@@ -262,6 +275,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void _HandleTogglePaneZoom(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleScrollUpPage(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleScrollDownPage(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleScrollToTop(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleScrollToBottom(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleOpenSettings(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandlePasteText(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleNewTab(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
@@ -273,7 +288,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void _HandleAdjustFontSize(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleFind(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleResetFontSize(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleToggleRetroEffect(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleToggleShaderEffects(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleToggleFocusMode(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleToggleFullscreen(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
void _HandleToggleAlwaysOnTop(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user