mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-07 14:50:55 +00:00
Compare commits
205 Commits
dev/lhecke
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c04f089953 | ||
|
|
310fa770d6 | ||
|
|
2649256931 | ||
|
|
842e70743f | ||
|
|
0980e47187 | ||
|
|
d88b426059 | ||
|
|
7fc9f9e189 | ||
|
|
3b02296c64 | ||
|
|
0672af9f15 | ||
|
|
0a30739670 | ||
|
|
754b5c0ae1 | ||
|
|
6f30689fbf | ||
|
|
915fa3f6db | ||
|
|
4b11bacea8 | ||
|
|
a0eb76322c | ||
|
|
e77bfa4392 | ||
|
|
0bb66c8880 | ||
|
|
58be7a46f7 | ||
|
|
4153896df5 | ||
|
|
73933910e2 | ||
|
|
cd2f1ab48f | ||
|
|
9d4e2f4b20 | ||
|
|
1010fd81ce | ||
|
|
41a443ab38 | ||
|
|
62fb815842 | ||
|
|
68e6608110 | ||
|
|
a88cf47994 | ||
|
|
8a22d3529f | ||
|
|
297018dd08 | ||
|
|
35f4bf2de2 | ||
|
|
176d546f2c | ||
|
|
5e49cb37e9 | ||
|
|
14675bb4f6 | ||
|
|
352aab12dc | ||
|
|
31b8f938ed | ||
|
|
cc6739520a | ||
|
|
7ba80e6ccb | ||
|
|
e866f3d28b | ||
|
|
199446e5e5 | ||
|
|
d3ba2fc3f5 | ||
|
|
36278a9199 | ||
|
|
059467d4ba | ||
|
|
51ec42661f | ||
|
|
ae356758b6 | ||
|
|
5343d560b0 | ||
|
|
978fd6e2ba | ||
|
|
35651bc92c | ||
|
|
a3fbc64384 | ||
|
|
8a1e8ace97 | ||
|
|
b6254f8294 | ||
|
|
3f17a38db7 | ||
|
|
fc9e871794 | ||
|
|
fe57d5ca73 | ||
|
|
a9d6b30baf | ||
|
|
26b287c4ca | ||
|
|
9fff54faef | ||
|
|
563b7312b6 | ||
|
|
0102ce9ac2 | ||
|
|
4d47cd5866 | ||
|
|
0a11643f1d | ||
|
|
338c5047d7 | ||
|
|
33589cd8db | ||
|
|
ad51b22f44 | ||
|
|
ec5d246b35 | ||
|
|
043d5cd484 | ||
|
|
b780d8ab7e | ||
|
|
6e451a2d4b | ||
|
|
99042d2f0c | ||
|
|
30dbd3b554 | ||
|
|
17075d6744 | ||
|
|
25a8851986 | ||
|
|
de5f7af25d | ||
|
|
94e74d22c6 | ||
|
|
badc00e83b | ||
|
|
e7796e7db3 | ||
|
|
de0f702c74 | ||
|
|
abf5d9423a | ||
|
|
4ff38c260f | ||
|
|
fefee50757 | ||
|
|
7c031a2893 | ||
|
|
88def9ddcd | ||
|
|
bb5f56e704 | ||
|
|
e5d7fd0230 | ||
|
|
7c1edbdb5f | ||
|
|
2dfa3da199 | ||
|
|
4db5e0eefd | ||
|
|
a6a0e44088 | ||
|
|
6b29ef51e3 | ||
|
|
ec434e3fba | ||
|
|
9c8058c326 | ||
|
|
bf25595961 | ||
|
|
9654fc6afe | ||
|
|
3f27765861 | ||
|
|
0ec73b1a6e | ||
|
|
d3ec47a7fc | ||
|
|
78da9bd965 | ||
|
|
5e9f223a6c | ||
|
|
23580749a4 | ||
|
|
e3ff44bb82 | ||
|
|
f30cbef34d | ||
|
|
d3a18b9041 | ||
|
|
bef234081a | ||
|
|
092b3558f3 | ||
|
|
c2446334e6 | ||
|
|
3982358188 | ||
|
|
71c35cf24c | ||
|
|
71efdcb21b | ||
|
|
ec91be5995 | ||
|
|
5dda50767b | ||
|
|
b70fd5e9c6 | ||
|
|
151da764ef | ||
|
|
438571bd7f | ||
|
|
ef96e225da | ||
|
|
01868978b3 | ||
|
|
26d35c3ac5 | ||
|
|
c669afe2a0 | ||
|
|
ce30e7c89c | ||
|
|
bcca7aac1b | ||
|
|
add1632d63 | ||
|
|
a2bb3136bb | ||
|
|
dccc1f4240 | ||
|
|
86c30bdaa2 | ||
|
|
bc48eda022 | ||
|
|
29895e1c2d | ||
|
|
5f71cf3e94 | ||
|
|
04edb112ea | ||
|
|
9c10575c73 | ||
|
|
a3ac337d88 | ||
|
|
5d2fa4782f | ||
|
|
7e46fa35f7 | ||
|
|
63bfdb2e1e | ||
|
|
5575187b26 | ||
|
|
48a6d92255 | ||
|
|
e727aaf679 | ||
|
|
98146c9d1b | ||
|
|
e6ac014fc8 | ||
|
|
0d47c862c2 | ||
|
|
a39ac598cd | ||
|
|
b08dc61a9c | ||
|
|
ba6f1e905d | ||
|
|
bc452c61dc | ||
|
|
204794f9f3 | ||
|
|
4902b342ef | ||
|
|
03aa8a6231 | ||
|
|
e75a4be4fe | ||
|
|
da99d892f4 | ||
|
|
f5898886be | ||
|
|
fe65d9ac8f | ||
|
|
6c192d15be | ||
|
|
da182e6c59 | ||
|
|
521a300c17 | ||
|
|
10fb5448cc | ||
|
|
a24afcd1e6 | ||
|
|
0d528f84f2 | ||
|
|
6bc711de06 | ||
|
|
f622d80004 | ||
|
|
4cec7e9b4b | ||
|
|
cf920e7d58 | ||
|
|
389ba20a98 | ||
|
|
dd8606ff9b | ||
|
|
7bc1457d42 | ||
|
|
e9e04d4e70 | ||
|
|
58e8f3c11c | ||
|
|
8df9523a77 | ||
|
|
fd0640997d | ||
|
|
fb74fc8c6a | ||
|
|
5f4087ff00 | ||
|
|
81889a685c | ||
|
|
e82c627ebe | ||
|
|
d726165330 | ||
|
|
57e1f26d14 | ||
|
|
b49997b4b4 | ||
|
|
2086e0f3af | ||
|
|
6107c3e551 | ||
|
|
46469aa5e3 | ||
|
|
c869b47e13 | ||
|
|
9531069538 | ||
|
|
521e301541 | ||
|
|
842326daa5 | ||
|
|
fb7c80938b | ||
|
|
29d0d57656 | ||
|
|
cbd61b0a7d | ||
|
|
1cc9835454 | ||
|
|
86914bdfc1 | ||
|
|
e0b003ad4d | ||
|
|
f89368c19b | ||
|
|
5582e1bcc8 | ||
|
|
a23c1a24dc | ||
|
|
5f9add4000 | ||
|
|
11126f9b37 | ||
|
|
e31202b0b8 | ||
|
|
e6dc314c17 | ||
|
|
2d4030683a | ||
|
|
262d95aae5 | ||
|
|
63ba8e19fd | ||
|
|
1b39db7ab0 | ||
|
|
2dd8f409b2 | ||
|
|
049c043279 | ||
|
|
a1da6c117e | ||
|
|
7c9ffb0e02 | ||
|
|
84df8197d4 | ||
|
|
5b3aa54b56 | ||
|
|
ef6bb8a73c | ||
|
|
4e144425f0 | ||
|
|
f353323a23 |
8
.github/actions/spelling/allow/allow.txt
vendored
8
.github/actions/spelling/allow/allow.txt
vendored
@@ -17,6 +17,8 @@ CMMI
|
||||
copyable
|
||||
Counterintuitively
|
||||
CtrlDToClose
|
||||
CVS
|
||||
CUI
|
||||
cybersecurity
|
||||
dalet
|
||||
Dcs
|
||||
@@ -80,19 +82,24 @@ noreply
|
||||
ogonek
|
||||
ok'd
|
||||
overlined
|
||||
perlw
|
||||
pipeline
|
||||
postmodern
|
||||
Powerline
|
||||
powerline
|
||||
ptys
|
||||
pwshw
|
||||
qof
|
||||
qps
|
||||
Remappings
|
||||
Retargets
|
||||
rclt
|
||||
reimplementation
|
||||
reserialization
|
||||
reserialize
|
||||
reserializes
|
||||
rlig
|
||||
rubyw
|
||||
runtimes
|
||||
servicebus
|
||||
shcha
|
||||
@@ -113,6 +120,7 @@ toolset
|
||||
truthiness
|
||||
tshe
|
||||
ubuntu
|
||||
UEFI
|
||||
uiatextrange
|
||||
UIs
|
||||
und
|
||||
|
||||
16
.github/actions/spelling/allow/apis.txt
vendored
16
.github/actions/spelling/allow/apis.txt
vendored
@@ -1,9 +1,12 @@
|
||||
aalt
|
||||
abvm
|
||||
ACCEPTFILES
|
||||
ACCESSDENIED
|
||||
acl
|
||||
aclapi
|
||||
alignas
|
||||
alignof
|
||||
allocconsolewithoptions
|
||||
APPLYTOSUBMENUS
|
||||
appxrecipe
|
||||
bitfield
|
||||
@@ -21,7 +24,9 @@ COLORPROPERTY
|
||||
colspan
|
||||
COMDLG
|
||||
commandlinetoargv
|
||||
commoncontrols
|
||||
comparand
|
||||
COPYFROMRESOURCE
|
||||
cstdint
|
||||
CXICON
|
||||
CYICON
|
||||
@@ -33,6 +38,7 @@ delayimp
|
||||
DERR
|
||||
dlldata
|
||||
DNE
|
||||
dnom
|
||||
DONTADDTORECENT
|
||||
DWMSBT
|
||||
DWMWA
|
||||
@@ -41,10 +47,12 @@ endfor
|
||||
ENDSESSION
|
||||
enumset
|
||||
environstrings
|
||||
EXACTSIZEONLY
|
||||
EXPCMDFLAGS
|
||||
EXPCMDSTATE
|
||||
filetime
|
||||
FILTERSPEC
|
||||
fina
|
||||
FORCEFILESYSTEM
|
||||
FORCEMINIMIZE
|
||||
frac
|
||||
@@ -58,6 +66,7 @@ Hashtable
|
||||
HIGHCONTRASTON
|
||||
HIGHCONTRASTW
|
||||
hinternet
|
||||
HIGHQUALITYSCALE
|
||||
HINTERNET
|
||||
hotkeys
|
||||
href
|
||||
@@ -74,6 +83,7 @@ IBox
|
||||
IClass
|
||||
IComparable
|
||||
IComparer
|
||||
ICONINFO
|
||||
IConnection
|
||||
ICustom
|
||||
IDialog
|
||||
@@ -83,6 +93,7 @@ IExplorer
|
||||
IFACEMETHOD
|
||||
IFile
|
||||
IGraphics
|
||||
IImage
|
||||
IInheritable
|
||||
IMap
|
||||
IMonarch
|
||||
@@ -113,6 +124,7 @@ LSHIFT
|
||||
LTGRAY
|
||||
MAINWINDOW
|
||||
MAXIMIZEBOX
|
||||
medi
|
||||
memchr
|
||||
memicmp
|
||||
MENUCOMMAND
|
||||
@@ -143,6 +155,7 @@ NOTIFYBYPOS
|
||||
NOTIFYICON
|
||||
NOTIFYICONDATA
|
||||
ntprivapi
|
||||
numr
|
||||
oaidl
|
||||
ocidl
|
||||
ODR
|
||||
@@ -156,6 +169,7 @@ OUTLINETEXTMETRICW
|
||||
overridable
|
||||
PACL
|
||||
PAGESCROLL
|
||||
PALLOC
|
||||
PATINVERT
|
||||
PEXPLICIT
|
||||
PICKFOLDERS
|
||||
@@ -167,9 +181,11 @@ REGCLS
|
||||
RETURNCMD
|
||||
rfind
|
||||
RLO
|
||||
rnrn
|
||||
ROOTOWNER
|
||||
roundf
|
||||
RSHIFT
|
||||
rvrn
|
||||
SACL
|
||||
schandle
|
||||
SEH
|
||||
|
||||
4
.github/actions/spelling/allow/microsoft.txt
vendored
4
.github/actions/spelling/allow/microsoft.txt
vendored
@@ -20,6 +20,7 @@ cpptools
|
||||
cppvsdbg
|
||||
CPRs
|
||||
cryptbase
|
||||
cscript
|
||||
DACL
|
||||
DACLs
|
||||
defaultlib
|
||||
@@ -45,6 +46,7 @@ MSAA
|
||||
msixbundle
|
||||
MSVC
|
||||
MSVCP
|
||||
mtu
|
||||
muxc
|
||||
netcore
|
||||
Onefuzz
|
||||
@@ -88,8 +90,10 @@ Virtualization
|
||||
visualstudio
|
||||
vscode
|
||||
VSTHRD
|
||||
WINBASEAPI
|
||||
winsdkver
|
||||
wlk
|
||||
wscript
|
||||
wslpath
|
||||
wtl
|
||||
wtt
|
||||
|
||||
1
.github/actions/spelling/excludes.txt
vendored
1
.github/actions/spelling/excludes.txt
vendored
@@ -115,6 +115,7 @@
|
||||
^src/terminal/parser/ut_parser/Base64Test.cpp$
|
||||
^src/terminal/parser/ut_parser/run\.bat$
|
||||
^src/tools/benchcat
|
||||
^src/tools/ConsoleBench
|
||||
^src/tools/integrity/dirs$
|
||||
^src/tools/integrity/packageuwp/ConsoleUWP\.appxSources$
|
||||
^src/tools/RenderingTests/main\.cpp$
|
||||
|
||||
24
.github/actions/spelling/expect/expect.txt
vendored
24
.github/actions/spelling/expect/expect.txt
vendored
@@ -19,6 +19,7 @@ AFew
|
||||
AFill
|
||||
AFX
|
||||
AHelper
|
||||
ahicon
|
||||
ahz
|
||||
AImpl
|
||||
AInplace
|
||||
@@ -183,6 +184,7 @@ chh
|
||||
chshdng
|
||||
CHT
|
||||
Cic
|
||||
CLASSSTRING
|
||||
CLE
|
||||
cleartype
|
||||
CLICKACTIVE
|
||||
@@ -319,6 +321,7 @@ ctlseqs
|
||||
CTRLEVENT
|
||||
CTRLFREQUENCY
|
||||
CTRLKEYSHORTCUTS
|
||||
Ctrls
|
||||
CTRLVOLUME
|
||||
Ctxt
|
||||
CUF
|
||||
@@ -401,6 +404,7 @@ DECECM
|
||||
DECEKBD
|
||||
DECERA
|
||||
DECFI
|
||||
DECFNK
|
||||
DECFRA
|
||||
DECIC
|
||||
DECID
|
||||
@@ -426,6 +430,7 @@ DECRQM
|
||||
DECRQPSR
|
||||
DECRQSS
|
||||
DECRQTSR
|
||||
DECRQUPSS
|
||||
DECRSPS
|
||||
decrst
|
||||
DECSACE
|
||||
@@ -443,10 +448,12 @@ DECSLPP
|
||||
DECSLRM
|
||||
DECSMKR
|
||||
DECSR
|
||||
DECST
|
||||
DECSTBM
|
||||
DECSTGLT
|
||||
DECSTR
|
||||
DECSWL
|
||||
DECSWT
|
||||
DECTABSR
|
||||
DECTCEM
|
||||
DECXCPR
|
||||
@@ -481,6 +488,7 @@ directio
|
||||
DIRECTX
|
||||
DISABLEDELAYEDEXPANSION
|
||||
DISABLENOSCROLL
|
||||
DISPATCHNOTIFY
|
||||
DISPLAYATTRIBUTE
|
||||
DISPLAYATTRIBUTEPROPERTY
|
||||
DISPLAYCHANGE
|
||||
@@ -838,6 +846,9 @@ IGNORELANGUAGE
|
||||
IHosted
|
||||
iid
|
||||
IIo
|
||||
ILC
|
||||
ILCo
|
||||
ILD
|
||||
ime
|
||||
IMPEXP
|
||||
inbox
|
||||
@@ -1111,8 +1122,8 @@ msix
|
||||
msrc
|
||||
MSVCRTD
|
||||
MTSM
|
||||
munged
|
||||
munges
|
||||
Munged
|
||||
murmurhash
|
||||
muxes
|
||||
myapplet
|
||||
@@ -1335,11 +1346,14 @@ pgomgr
|
||||
PGONu
|
||||
pguid
|
||||
phhook
|
||||
phico
|
||||
phicon
|
||||
phwnd
|
||||
pidl
|
||||
PIDLIST
|
||||
pids
|
||||
pii
|
||||
piml
|
||||
pinvoke
|
||||
pipename
|
||||
pipestr
|
||||
@@ -1671,6 +1685,8 @@ slpit
|
||||
SManifest
|
||||
SMARTQUOTE
|
||||
SMTO
|
||||
snapcx
|
||||
snapcy
|
||||
SOLIDBOX
|
||||
Solutiondir
|
||||
somefile
|
||||
@@ -1868,7 +1884,12 @@ uiautomationcore
|
||||
uielem
|
||||
UIELEMENTENABLEDONLY
|
||||
UINTs
|
||||
ul
|
||||
ulcch
|
||||
uld
|
||||
uldb
|
||||
uldash
|
||||
ulwave
|
||||
Unadvise
|
||||
unattend
|
||||
UNCPRIORITY
|
||||
@@ -1891,6 +1912,7 @@ UPDATEDISPLAY
|
||||
UPDOWN
|
||||
UPKEY
|
||||
UPSS
|
||||
upss
|
||||
uregex
|
||||
URegular
|
||||
usebackq
|
||||
|
||||
473
OpenConsole.sln
473
OpenConsole.sln
File diff suppressed because it is too large
Load Diff
34
Scratch.sln
34
Scratch.sln
@@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Package", "scratch\ScratchIslandApp\Package\Package.wapproj", "{CF31505E-3BAE-4C0A-81D7-F1EB279F40BB}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleAppLib", "scratch\ScratchIslandApp\SampleApp\SampleAppLib.vcxproj", "{A4394404-37F7-41C1-802B-49788D3720E3}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3} = {7CAE5851-50D5-4934-8D5E-30361A8A40F3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleApp", "scratch\ScratchIslandApp\SampleApp\dll\SampleApp.vcxproj", "{26C51792-41A3-4FE0-AB5E-8B69D557BF91}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
@@ -31,6 +34,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common Props", "Common Prop
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxproj", "{6BAE5851-50D5-4934-8D5E-30361A8A40F3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md4c", "src\dep\md4c\md4c.vcxproj", "{7CAE5851-50D5-4934-8D5E-30361A8A40F3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types", "src\types\lib\types.vcxproj", "{18D09A24-8240-42D6-8CB6-236EEE820263}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}"
|
||||
@@ -183,6 +188,34 @@ Global
|
||||
{6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64
|
||||
{6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32
|
||||
{6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32
|
||||
|
||||
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.Build.0 = AuditMode|x64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.ActiveCfg = AuditMode|Win32
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.Build.0 = AuditMode|Win32
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.Build.0 = Debug|x64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.Build.0 = Debug|Win32
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.Build.0 = Fuzzing|x64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.Build.0 = Fuzzing|Win32
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.ActiveCfg = Release|x64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32
|
||||
|
||||
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|x64.ActiveCfg = AuditMode|x64
|
||||
@@ -213,6 +246,7 @@ Global
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}
|
||||
{7CAE5851-50D5-4934-8D5E-30361A8A40F3} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}
|
||||
{18D09A24-8240-42D6-8CB6-236EEE820263} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
|
||||
- template: steps-ensure-nuget-version.yml
|
||||
|
||||
- task: NuGetAuthenticate@0
|
||||
- task: NuGetAuthenticate@1
|
||||
inputs:
|
||||
nuGetServiceConnections: 'Terminal Public Artifact Feed'
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ jobs:
|
||||
- task: PowerShell@2
|
||||
displayName: 'Run PGO Tests'
|
||||
inputs:
|
||||
pwsh: true
|
||||
targetType: filePath
|
||||
filePath: build\scripts\Run-Tests.ps1
|
||||
arguments: >-
|
||||
|
||||
@@ -44,6 +44,7 @@ jobs:
|
||||
- task: PowerShell@2
|
||||
displayName: 'Run Unit Tests'
|
||||
inputs:
|
||||
pwsh: true
|
||||
targetType: filePath
|
||||
filePath: build\scripts\Run-Tests.ps1
|
||||
arguments: -MatchPattern '*unit.test*.dll' -Platform '$(OutputBuildPlatform)' -Configuration '$(BuildConfiguration)' -LogPath '${{ parameters.testLogPath }}' -Root "$(Terminal.BinDir)"
|
||||
@@ -52,6 +53,7 @@ jobs:
|
||||
- task: PowerShell@2
|
||||
displayName: 'Run Feature Tests'
|
||||
inputs:
|
||||
pwsh: true
|
||||
targetType: filePath
|
||||
filePath: build\scripts\Run-Tests.ps1
|
||||
arguments: -MatchPattern '*feature.test*.dll' -Platform '$(OutputBuildPlatform)' -Configuration '$(BuildConfiguration)' -LogPath '${{ parameters.testLogPath }}' -Root "$(Terminal.BinDir)"
|
||||
|
||||
@@ -78,6 +78,9 @@ extends:
|
||||
cloudvault: # https://aka.ms/obpipelines/cloudvault
|
||||
enabled: false
|
||||
globalSdl: # https://aka.ms/obpipelines/sdl
|
||||
asyncSdl:
|
||||
enabled: true
|
||||
tsaOptionsFile: 'build/config/tsa.json'
|
||||
tsa:
|
||||
enabled: true
|
||||
configFile: '$(Build.SourcesDirectory)\build\config\tsa.json'
|
||||
@@ -247,7 +250,7 @@ extends:
|
||||
|
||||
- stage: Publish
|
||||
displayName: Publish
|
||||
dependsOn: [Build, Package]
|
||||
dependsOn: [Build]
|
||||
jobs:
|
||||
- template: ./build/pipelines/templates-v2/job-publish-symbols.yml@self
|
||||
parameters:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
steps:
|
||||
- template: steps-ensure-nuget-version.yml
|
||||
|
||||
- task: NuGetAuthenticate@0
|
||||
- task: NuGetAuthenticate@1
|
||||
|
||||
- script: |-
|
||||
echo ##vso[task.setvariable variable=NUGET_RESTORE_MSBUILD_ARGS]/p:Platform=$(BuildPlatform)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<IntermediateOutputPath>$(SolutionDir)obj\$(Configuration)\GenerateFeatureFlags\</IntermediateOutputPath>
|
||||
<OpenConsoleCommonOutDir>$(SolutionDir)bin\$(Configuration)\</OpenConsoleCommonOutDir>
|
||||
|
||||
<_WTBrandingName Condition="'$(WindowsTerminalBranding)'=='Canary'">Canary</_WTBrandingName>
|
||||
<_WTBrandingName Condition="'$(WindowsTerminalBranding)'=='Preview'">Preview</_WTBrandingName>
|
||||
<_WTBrandingName Condition="'$(WindowsTerminalBranding)'=='Release'">Release</_WTBrandingName>
|
||||
<_WTBrandingName Condition="'$(_WTBrandingName)'==''">Dev</_WTBrandingName>
|
||||
|
||||
@@ -16,22 +16,48 @@ Param(
|
||||
# Find test DLLs based on the provided root, match pattern, and recursion
|
||||
$testDlls = Get-ChildItem -Path $Root -Recurse -Filter $MatchPattern
|
||||
|
||||
$args = @()
|
||||
$teArgs = @()
|
||||
|
||||
# Check if the LogPath parameter is provided and enable WTT logging
|
||||
if ($LogPath) {
|
||||
$args += '/enablewttlogging'
|
||||
$args += '/appendwttlogging'
|
||||
$args += "/logFile:$LogPath"
|
||||
$teArgs += '/enablewttlogging'
|
||||
$teArgs += '/appendwttlogging'
|
||||
$teArgs += "/logFile:$LogPath"
|
||||
Write-Host "WTT Logging Enabled"
|
||||
}
|
||||
|
||||
# Invoke the te.exe executable with arguments and test DLLs
|
||||
& "$Root\te.exe" $args $testDlls.FullName $AdditionalTaefArguments
|
||||
$rootTe = "$Root\te.exe"
|
||||
|
||||
# Check the exit code of the te.exe process and exit accordingly
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Exit $LASTEXITCODE
|
||||
# Some of our test fixtures depend on resources.pri in the same folder as the .exe hosting them.
|
||||
# Unfortunately, that means that we need to run the te.exe *next to* each test DLL we discover.
|
||||
# This code establishes a mapping from te.exe to test DLL (or DLLs)
|
||||
$testDllTaefGroups = $testDlls | % {
|
||||
$localTe = Get-Item (Join-Path (Split-Path $_ -Parent) "te.exe") -EA:Ignore
|
||||
If ($null -eq $localTe) {
|
||||
$finalTePath = $rootTe
|
||||
} Else {
|
||||
$finalTePath = $localTe.FullName
|
||||
}
|
||||
[PSCustomObject]@{
|
||||
TePath = $finalTePath;
|
||||
TestDll = $_;
|
||||
}
|
||||
}
|
||||
|
||||
# Invoke the te.exe executables with arguments and test DLLs
|
||||
$anyFailed = $false
|
||||
$testDllTaefGroups | Group-Object TePath | % {
|
||||
$te = $_.Group[0].TePath
|
||||
$dlls = $_.Group.TestDll
|
||||
Write-Verbose "Running $te (for $($dlls.Name))"
|
||||
& $te $teArgs $dlls.FullName $AdditionalTaefArguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
$anyFailed = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($anyFailed) {
|
||||
Exit 1
|
||||
}
|
||||
|
||||
Exit 0
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
<!-- This file is read by XES, which we use in our Release builds. -->
|
||||
<PropertyGroup Label="Version">
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2023</XesBaseYearForStoreVersion>
|
||||
<XesBaseYearForStoreVersion>2024</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>20</VersionMinor>
|
||||
<VersionMinor>21</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<package id="Microsoft.VisualStudio.Setup.Configuration.Native" version="2.3.2262" targetFramework="native" developmentDependency="true" />
|
||||
<package id="Microsoft.UI.Xaml" version="2.8.4" targetFramework="native" />
|
||||
<package id="Microsoft.Web.WebView2" version="1.0.1661.34" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.230824.2" targetFramework="native" developmentDependency="true" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.240122.1" targetFramework="native" developmentDependency="true" />
|
||||
|
||||
<!-- Managed packages -->
|
||||
<package id="Appium.WebDriver" version="3.0.0.2" targetFramework="net45" />
|
||||
|
||||
@@ -2782,15 +2782,15 @@
|
||||
"description": "When set to true, marks added to the buffer via the addMark action will appear on the scrollbar.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.repositionCursorWithMouse": {
|
||||
"default": false,
|
||||
"description": "When set to true, you can move the text cursor by clicking with the mouse on the current commandline. This is an experimental feature - there are lots of edge cases where this will not work as expected.",
|
||||
"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"
|
||||
},
|
||||
"useAtlasEngine": {
|
||||
"description": "Windows Terminal 1.16 and later ship with a new, performant text renderer. Set this to false to revert back to the old text renderer.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"fontFace": {
|
||||
"default": "Cascadia Mono",
|
||||
"description": "[deprecated] Define 'face' within the 'font' object instead.",
|
||||
|
||||
396
doc/specs/#7335 - Console Allocation Policy.md
Normal file
396
doc/specs/#7335 - Console Allocation Policy.md
Normal file
@@ -0,0 +1,396 @@
|
||||
---
|
||||
author: Dustin Howett @DHowett <duhowett@microsoft.com>
|
||||
created on: 2020-08-16
|
||||
last updated: 2023-12-12
|
||||
issue id: "#7335"
|
||||
---
|
||||
|
||||
# Console Allocation Policy
|
||||
|
||||
## Abstract
|
||||
|
||||
Due to the design of the console subsystem on Windows as it has existed since Windows 95, every application that is
|
||||
stamped with the `IMAGE_SUBSYSTEM_WINDOWS_CUI` subsystem in its PE header will be allocated a console by kernel32.
|
||||
|
||||
Any application that is stamped `IMAGE_SUBSYSTEM_WINDOWS_GUI` will not automatically be allocated a console.
|
||||
|
||||
This has worked fine for many years: when you double-click a console application in your GUI shell, it is allocated a
|
||||
console. When you run a GUI application from your console shell, it is **not** allocated a console. The shell will
|
||||
**not** wait for it to exit before returning you to a prompt.
|
||||
|
||||
There is a large class of applications that do not fit neatly into this mold. Take Python, Ruby, Perl, Lua, or even
|
||||
VBScript: These languages are not relegated to running in a console session; they can be used to write fully-fledged GUI
|
||||
applications like any other language.
|
||||
|
||||
Because their interpreters are console subsystem applications, however, any user double-clicking a shortcut to a Python
|
||||
or Perl application will be presented with a console window that the language runtime may choose to garbage collect, or
|
||||
may choose not to.
|
||||
|
||||
If the runtime chooses to hide the window, there will still be a brief period during which that window is visible. It is
|
||||
inescapable.
|
||||
|
||||
Likewise, any user running that GUI application from a console shell will see their shell hang until the application
|
||||
terminates.
|
||||
|
||||
All of these scripting languages worked around this by shipping two binaries each, identical in every way expect in
|
||||
their subsystem fields. python/pythonw, perl/perlw, ruby/rubyw, wscript/cscript.
|
||||
|
||||
PowerShell[^1] is waiting to deal with this problem because they don't necessarily want to ship a `pwshw.exe` for all
|
||||
of their GUI-only authors. Every additional `*w` version of an application is an additional maintenance burden and
|
||||
source of cognitive overhead[^2] for users.
|
||||
|
||||
On the other side, you have mostly-GUI applications that want to print output to a console **if there is one
|
||||
connected**.
|
||||
|
||||
These applications are still primarily GUI-driven, but they might support arguments like `/?` or `--help`. They only
|
||||
need a console when they need to print out some text. Sometimes they'll allocate their own console (which opens a new
|
||||
window) to display in, and sometimes they'll reattach to the originating console. VSCode does the latter, and so when
|
||||
you run `code` from CMD, and then `exit` CMD, your console window sticks around because VSCode is still attached to it.
|
||||
It will never print anything, and your only option is to close it.
|
||||
|
||||
There's another risk in reattaching, too. Given that the shell decides whether to wait based on the subsystem
|
||||
field, GUI subsystem applications that reattach to their owning consoles *just to print some text* end up stomping on
|
||||
the output of any shell that doesn't wait for them:
|
||||
|
||||
```
|
||||
C:\> application --help
|
||||
|
||||
application - the interesting application
|
||||
C:\> Usage: application [OPTIONS] ...
|
||||
```
|
||||
|
||||
> _(the prompt is interleaved with the output)_
|
||||
|
||||
## Solution Design
|
||||
|
||||
I propose that we introduce a fusion manifest field, **consoleAllocationPolicy**, with the following values:
|
||||
|
||||
* _absent_
|
||||
* `detached`
|
||||
|
||||
This field allows an application to disable the automatic allocation of a console, regardless of the [process creation flags]
|
||||
passed to [`CreateProcess`] and its subsystem value.
|
||||
|
||||
It would look (roughly) like this:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<application>
|
||||
<windowsSettings>
|
||||
<consoleAllocationPolicy xmlns="http://schemas.microsoft.com/SMI/2024/WindowsSettings">detached</consoleAllocationPolicy>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
```
|
||||
|
||||
The effects of this field will only apply to binaries in the `IMAGE_SUBSYSTEM_WINDOWS_CUI` subsystem, as it pertains to
|
||||
the particulars of their console allocation.
|
||||
|
||||
**All console inheritance will proceed as normal.** Since this field takes effect only in the absence of console
|
||||
inheritance, CUI applications will still be able to run inside an existing console session.
|
||||
|
||||
| policy | behavior |
|
||||
| - | - |
|
||||
| _absent_ | _default behavior_ |
|
||||
| `detached` | The new process is not attached to a console session (similar to `DETACHED_PROCESS`) unless one was inherited. |
|
||||
|
||||
An application that specifies the `detached` allocation policy will _not_ present a console window when launched by
|
||||
Explorer, Task Scheduler, etc.
|
||||
|
||||
### Interaction with existing APIs
|
||||
|
||||
[`CreateProcess`] supports a number of [process creation flags] that dictate how a spawned application will behave with
|
||||
regards to console allocation:
|
||||
|
||||
* `DETACHED_PROCESS`: No console inheritance, no console host spawned for the new process.
|
||||
* `CREATE_NEW_CONSOLE`: No console inheritance, new console host **is** spawned for the new process.
|
||||
* `CREATE_NO_WINDOW`: No console inheritance, new console host **is** spawned for the new process.
|
||||
* this is the same as `CREATE_NEW_CONSOLE`, except that the first connection packet specifies that the window should
|
||||
be invisible
|
||||
|
||||
Due to the design of [`CreateProcess`] and `ShellExecute`, this specification recommends that an allocation policy of
|
||||
`detached` _override_ the inclusion of `CREATE_NEW_CONSOLE` in the `dwFlags` parameter to [`CreateProcess`].
|
||||
|
||||
> **Note**
|
||||
> `ShellExecute` passes `CREATE_NEW_CONSOLE` _by default_ on all invocations. This impacts our ability to resolve the
|
||||
> conflicts between these two APIs--`detached` policy and `CREATE_NEW_CONSOLE`--without auditing every call site in
|
||||
> every Windows application that calls `ShellExecute` on a console application. Doing so is infeasible.
|
||||
|
||||
### Application impact
|
||||
|
||||
An application that opts into the `detached` console allocation policy will **not** be allocated a console unless one is
|
||||
inherited. This presents an issue for applications like PowerShell that do want a console window when they are launched
|
||||
directly.
|
||||
|
||||
Applications in this category can call `AllocConsole()` early in their startup to get fine-grained control over when a
|
||||
console is presented.
|
||||
|
||||
The call to `AllocConsole()` will fail safely if the application has already inherited a console handle. It will succeed
|
||||
if the application does not currently have a console handle.
|
||||
|
||||
> **Note**
|
||||
> **Backwards Compatibility**: The behavior of `AllocConsole()` is not changing in response to this specification;
|
||||
> therefore, applications that intend to run on older versions of Windows that do not support console allocation
|
||||
> policies, which call `AllocConsole()`, will continue to behave normally.
|
||||
|
||||
### New APIs
|
||||
|
||||
Because a console-subsystem application may still want fine-grained control over when and how its console window is
|
||||
spawned, we propose the inclusion of a new API, `AllocConsoleWithOptions(PALLOC_CONSOLE_OPTIONS)`.
|
||||
|
||||
#### `AllocConsoleWithOptions`
|
||||
|
||||
```c++
|
||||
// Console Allocation Modes
|
||||
typedef enum ALLOC_CONSOLE_MODE {
|
||||
ALLOC_CONSOLE_MODE_DEFAULT = 0,
|
||||
ALLOC_CONSOLE_MODE_NEW_WINDOW = 1,
|
||||
ALLOC_CONSOLE_MODE_NO_WINDOW = 2
|
||||
} ALLOC_CONSOLE_MODE;
|
||||
|
||||
typedef enum ALLOC_CONSOLE_RESULT {
|
||||
ALLOC_CONSOLE_RESULT_NO_CONSOLE = 0,
|
||||
ALLOC_CONSOLE_RESULT_NEW_CONSOLE = 1,
|
||||
ALLOC_CONSOLE_RESULT_EXISTING_CONSOLE = 2
|
||||
} ALLOC_CONSOLE_RESULT, *PALLOC_CONSOLE_RESULT;
|
||||
|
||||
typedef
|
||||
struct ALLOC_CONSOLE_OPTIONS
|
||||
{
|
||||
ALLOC_CONSOLE_MODE mode;
|
||||
BOOL useShowWindow;
|
||||
WORD showWindow;
|
||||
} ALLOC_CONSOLE_OPTIONS, *PALLOC_CONSOLE_OPTIONS;
|
||||
|
||||
WINBASEAPI
|
||||
HRESULT
|
||||
WINAPI
|
||||
AllocConsoleWithOptions(_In_opt_ PALLOC_CONSOLE_OPTIONS allocOptions, _Out_opt_ PALLOC_CONSOLE_RESULT result);
|
||||
```
|
||||
|
||||
**AllocConsoleWithOptions** affords an application control over how and when it begins a console session.
|
||||
|
||||
> [!NOTE]
|
||||
> Unlike `AllocConsole`, `AllocConsoleWithOptions` without a mode (`ALLOC_CONSOLE_MODE_DEFAULT`) will only allocate a console if one was
|
||||
> requested during `CreateProcess`.
|
||||
>
|
||||
> To override this behavior, pass one of `ALLOC_CONSOLE_MODE_NEW_WINDOW` (which is equivalent to being spawned with
|
||||
> `CREATE_NEW_WINDOW`) or `ALLOC_CONSOLE_MODE_NO_WINDOW` (which is equivalent to being spawned with `CREATE_NO_CONSOLE`.)
|
||||
|
||||
##### Parameters
|
||||
|
||||
**allocOptions**: A pointer to a `ALLOC_CONSOLE_OPTIONS`.
|
||||
|
||||
**result**: An optional out pointer, which will be populated with a member of the `ALLOC_CONSOLE_RESULT` enum.
|
||||
|
||||
##### `ALLOC_CONSOLE_OPTIONS`
|
||||
|
||||
###### Members
|
||||
|
||||
**mode**: See the table below for the descriptions of the available modes.
|
||||
|
||||
**useShowWindow**: Specifies whether the value in `showWindow` should be used.
|
||||
|
||||
**showWindow**: If `useShowWindow` is set, specifies the ["show command"] used to display your
|
||||
console window.
|
||||
|
||||
###### Return Value
|
||||
|
||||
`AllocConsoleWithOptions` will return `S_OK` and populate `result` to indicate whether--and how--a console session was
|
||||
created.
|
||||
|
||||
`AllocConsoleWithOptions` will return a failing `HRESULT` if the request could not be completed.
|
||||
|
||||
###### Modes
|
||||
|
||||
| Mode | Description |
|
||||
|:-------------------------------:| ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `ALLOC_CONSOLE_MODE_DEFAULT` | Allocate a console session if (and how) one was requested by the parent process. |
|
||||
| `ALLOC_CONSOLE_MODE_NEW_WINDOW` | Allocate a console session with a window, even if this process was created with `CREATE_NO_CONSOLE` or `DETACHED_PROCESS`. |
|
||||
| `ALLOC_CONSOLE_MODE_NO_WINDOW` | Allocate a console session _without_ a window, even if this process was created with `CREATE_NEW_WINDOW` or `DETACHED_PROCESS` |
|
||||
|
||||
###### Notes
|
||||
|
||||
Applications seeking backwards compatibility are encouraged to delay-load `AllocConsoleWithOptions` or check for its presence in
|
||||
the `api-ms-win-core-console-l1` APISet.
|
||||
|
||||
## Inspiration
|
||||
|
||||
Fusion manifest entries are used to make application-scoped decisions like this all the time, like `longPathAware` and
|
||||
`heapType`.
|
||||
|
||||
CUI applications that can spawn a UI (or GUI applications that can print to a console) are commonplace on other
|
||||
platforms because there is no subsystem differentiation.
|
||||
|
||||
## UI/UX Design
|
||||
|
||||
There is no UI for this feature.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Accessibility
|
||||
|
||||
This should have no impact on accessibility.
|
||||
|
||||
### Security
|
||||
|
||||
One reviewer brought up the potential for a malicious actor to spawn an endless stream of headless daemon processes.
|
||||
|
||||
This proposal in no way changes the facilities available to malicious people for causing harm: they could have simply
|
||||
used `IMAGE_SUBSYSTEM_WINDOWS_GUI` and not presented a UI--an option that has been available to them for 35 years.
|
||||
|
||||
### Reliability
|
||||
|
||||
This should have no impact on reliability.
|
||||
|
||||
### Compatibility
|
||||
|
||||
An existing application opting into **detached** may constitute a breaking change, but the scope of the breakage is
|
||||
restricted to that application and is expected to be managed by the application.
|
||||
|
||||
All behavioral changes are opt-in.
|
||||
|
||||
> **EXAMPLE**: If Python updates python.exe to specify an allocation policy of **detached**, graphical python applications
|
||||
> will become double-click runnable from the graphical shell without spawning a console window. _However_, console-based
|
||||
> python applications will no longer spawn a console window when double-clicked from the graphical shell.
|
||||
>
|
||||
> In addition, if python.exe specifies **detached**, Console APIs will fail until a console is allocated.
|
||||
|
||||
Python could work around this by calling [`AllocConsole`] or [new API `AllocConsoleWithOptions`](#allocconsolewithoptions)
|
||||
if it can be detected that console I/O is required.
|
||||
|
||||
#### Downlevel
|
||||
|
||||
On downlevel versions of Windows that do not understand (or expect) this manifest field, applications will allocate
|
||||
consoles as specified by their image subsystem (described in the [abstract](#abstract) above).
|
||||
|
||||
### Performance, Power, and Efficiency
|
||||
|
||||
This should have no impact on performance, power or efficiency.
|
||||
|
||||
## Potential Issues
|
||||
|
||||
### Shell Hang
|
||||
|
||||
I am **not** proposing a change in how shells determine whether to wait for an application before returning to a prompt.
|
||||
This means that a console subsystem application that intends to primarily present a UI but occasionally print text to a
|
||||
console (therefore choosing the **detached** allocation policy) will cause the shell to "hang" and wait for it to
|
||||
exit.
|
||||
|
||||
The decision to pause/wait is made entirely in the calling shell, and the console subsystem cannot influence that
|
||||
decision.
|
||||
|
||||
Because the vast majority of shells on Windows "hang" by calling `WaitFor...Object` with a HANDLE to the spawned
|
||||
process, an application that wants to be a "hybrid" CUI/GUI application will be forced to spawn a separate process to
|
||||
detach from the shell and then terminate its main process.
|
||||
|
||||
This is very similar to the forking model seen in many POSIX-compliant operating systems.
|
||||
|
||||
### Launching interactively from Explorer, Task Scheduler, etc.
|
||||
|
||||
Applications like PowerShell may wish to retain automatic console allocation, and **detached** would be unsuitable for
|
||||
them. If PowerShell specifies the `detached` console allocation policy, launching `pwsh.exe` from File Explorer it will
|
||||
no longer spawn a console. This would almost certainly break PowerShell for all users.
|
||||
|
||||
Such applications can use `AllocConsole()` early in their startup.
|
||||
|
||||
At the same time, PowerShell wants `-WindowStyle Hidden` to suppress the console _before it's created_.
|
||||
|
||||
Applications in this category can use `AllocConsoleWithOptions()` to specify additional information about the new console window.
|
||||
|
||||
PowerShell, and any other shell that wishes to maintain interactive launch from the graphical shell, can start in
|
||||
**detached** mode and then allocate a console as necessary. Therefore:
|
||||
|
||||
* PowerShell will set `<consoleAllocationPolicy>detached</consoleAllocationPolicy>`
|
||||
* On startup, it will process its commandline arguments.
|
||||
* If `-WindowStyle Hidden` is **not** present (the default case), it can:
|
||||
* `AllocConsole()` or `AllocConsoleWithOptions(NULL)`
|
||||
* Either of these APIs will present a console window (or not) based on the flags passed through `STARTUPINFO` during
|
||||
[`CreateProcess`].
|
||||
* If `-WindowStyle Hidden` is present, it can:
|
||||
* `AllocConsoleWithOptions(&alloc)` where `alloc.mode` specifies `ALLOC_CONSOLE_MODE_HIDDEN`
|
||||
|
||||
## Future considerations
|
||||
|
||||
We're introducing a new manifest field today -- what if we want to introduce more? Should we have a `consoleSettings`
|
||||
manifest block?
|
||||
|
||||
Are there other allocation policies we need to consider?
|
||||
|
||||
## Resources
|
||||
|
||||
### Rejected Solutions
|
||||
|
||||
- A new PE subsystem, `IMAGE_SUBSYSTEM_WINDOWS_HYBRID`
|
||||
- it would behave like **inheritOnly**
|
||||
- relies on shells to update and check for this
|
||||
- checking a subsystem doesn't work right with app execution aliases[^3]
|
||||
- This is not a new problem, but it digs the hole a little deeper.
|
||||
- requires standardization outside of Microsoft because the PE format is a dependency of the UEFI specification[^4]
|
||||
- requires coordination between tooling teams both within and without Microsoft (regarding any tool that operates on
|
||||
or produces PE files)
|
||||
|
||||
- An exported symbol that shells can check for to determine whether to wait for the attached process to exit
|
||||
- relies on shells to update and check for this
|
||||
- cracking an executable to look for symbols is probably the last thing shells want to do
|
||||
- we could provide an API to determine whether to wait or return?
|
||||
- fragile, somewhat silly, exporting symbols from EXEs is annoying and uncommon
|
||||
|
||||
An earlier version of this specification offered the **always** allocation policy, with the following behaviors:
|
||||
|
||||
> **STRUCK FROM SPECIFICATION**
|
||||
>
|
||||
> * A GUI subsystem application would always get a console window.
|
||||
> * A command-line shell would not wait for it to exit before returning a prompt.
|
||||
|
||||
It was cut because a GUI application that wants a console window can simply attach to an existing console session or
|
||||
allocate a new one. We found no compelling use case that would require the forced allocation of a console session
|
||||
outside of the application's code.
|
||||
|
||||
An earlier version of this specification offered the **inheritOnly** allocation policy, instead of the finer-grained
|
||||
**hidden** and **detached** policies. We deemed it insufficient for PowerShell's use case because any application
|
||||
launched by an **inheritOnly** PowerShell would immediately force the uncontrolled allocation of a console window.
|
||||
|
||||
> **STRUCK FROM SPECIFICATION**
|
||||
>
|
||||
> The move to **hidden** allows PowerShell to offer a fully-fledged console connection that can be itself inherited by a
|
||||
> downstream application.
|
||||
|
||||
#### Additional allocation policies
|
||||
|
||||
An earlier revision of this specification suggested two allocation policies:
|
||||
|
||||
> **STRUCK FROM SPECIFICATION**
|
||||
>
|
||||
> **hidden** is intended to be used by console applications that want finer-grained control over the visibility of their
|
||||
> console windows, but that still need a console host to service console APIs. This includes most scripting language
|
||||
> interpreters.
|
||||
>
|
||||
> **detached** is intended to be used by primarily graphical applications that would like to operate against a console _if
|
||||
> one is present_ but do not mind its absence. This includes any graphical tool with a `--help` or `/?` argument.
|
||||
|
||||
The `hidden` policy was rejected due to an incompatibility with modern console hosting, as `hidden` would require an
|
||||
application to interact with the console window via `GetConsoleWindow()` and explicitly show it.
|
||||
|
||||
> **STRUCK FROM SPECIFICATION**
|
||||
>
|
||||
> ##### ShowWindow and ConPTY
|
||||
>
|
||||
> The pseudoconsole creates a hidden window to service `GetConsoleWindow()`, and it can be trivially shown using
|
||||
> `ShowWindow`. If we recommend that applications `ShowWindow` on startup, we will need to guard the pseudoconsole's
|
||||
> pseudo-window from being shown.
|
||||
|
||||
[^1]: [Powershell -WindowStyle Hidden still shows a window briefly]
|
||||
[^2]: [StackOverflow: pythonw.exe or python.exe?]
|
||||
[^3]: [PowerShell: Windows Store applications incorrectly assumed to be console applications]
|
||||
[^4]: [UEFI spec 2.6 appendix Q.1]
|
||||
|
||||
[Powershell -WindowStyle Hidden still shows a window briefly]: https://github.com/PowerShell/PowerShell/issues/3028
|
||||
[PowerShell: Windows Store applications incorrectly assumed to be console applications]: https://github.com/PowerShell/PowerShell/issues/9970
|
||||
[StackOverflow: pythonw.exe or python.exe?]: https://stackoverflow.com/questions/9705982/pythonw-exe-or-python-exe
|
||||
[UEFI spec 2.6 appendix Q.1]: https://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf
|
||||
[`AllocConsole`]: https://docs.microsoft.com/windows/console/allocconsole
|
||||
[`CreateProcess`]: https://docs.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
|
||||
[process creation flags]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
|
||||
["show command"]: https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-showwindow
|
||||
6492
oss/md4c/md4c.c
Normal file
6492
oss/md4c/md4c.c
Normal file
File diff suppressed because it is too large
Load Diff
407
oss/md4c/md4c.h
Normal file
407
oss/md4c/md4c.h
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* MD4C: Markdown parser for C
|
||||
* (http://github.com/mity/md4c)
|
||||
*
|
||||
* Copyright (c) 2016-2024 Martin Mitáš
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MD4C_H
|
||||
#define MD4C_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined MD4C_USE_UTF16
|
||||
/* Magic to support UTF-16. Note that in order to use it, you have to define
|
||||
* the macro MD4C_USE_UTF16 both when building MD4C as well as when
|
||||
* including this header in your code. */
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
typedef WCHAR MD_CHAR;
|
||||
#else
|
||||
#error MD4C_USE_UTF16 is only supported on Windows.
|
||||
#endif
|
||||
#else
|
||||
typedef char MD_CHAR;
|
||||
#endif
|
||||
|
||||
typedef unsigned MD_SIZE;
|
||||
typedef unsigned MD_OFFSET;
|
||||
|
||||
|
||||
/* Block represents a part of document hierarchy structure like a paragraph
|
||||
* or list item.
|
||||
*/
|
||||
typedef enum MD_BLOCKTYPE {
|
||||
/* <body>...</body> */
|
||||
MD_BLOCK_DOC = 0,
|
||||
|
||||
/* <blockquote>...</blockquote> */
|
||||
MD_BLOCK_QUOTE,
|
||||
|
||||
/* <ul>...</ul>
|
||||
* Detail: Structure MD_BLOCK_UL_DETAIL. */
|
||||
MD_BLOCK_UL,
|
||||
|
||||
/* <ol>...</ol>
|
||||
* Detail: Structure MD_BLOCK_OL_DETAIL. */
|
||||
MD_BLOCK_OL,
|
||||
|
||||
/* <li>...</li>
|
||||
* Detail: Structure MD_BLOCK_LI_DETAIL. */
|
||||
MD_BLOCK_LI,
|
||||
|
||||
/* <hr> */
|
||||
MD_BLOCK_HR,
|
||||
|
||||
/* <h1>...</h1> (for levels up to 6)
|
||||
* Detail: Structure MD_BLOCK_H_DETAIL. */
|
||||
MD_BLOCK_H,
|
||||
|
||||
/* <pre><code>...</code></pre>
|
||||
* Note the text lines within code blocks are terminated with '\n'
|
||||
* instead of explicit MD_TEXT_BR. */
|
||||
MD_BLOCK_CODE,
|
||||
|
||||
/* Raw HTML block. This itself does not correspond to any particular HTML
|
||||
* tag. The contents of it _is_ raw HTML source intended to be put
|
||||
* in verbatim form to the HTML output. */
|
||||
MD_BLOCK_HTML,
|
||||
|
||||
/* <p>...</p> */
|
||||
MD_BLOCK_P,
|
||||
|
||||
/* <table>...</table> and its contents.
|
||||
* Detail: Structure MD_BLOCK_TABLE_DETAIL (for MD_BLOCK_TABLE),
|
||||
* structure MD_BLOCK_TD_DETAIL (for MD_BLOCK_TH and MD_BLOCK_TD)
|
||||
* Note all of these are used only if extension MD_FLAG_TABLES is enabled. */
|
||||
MD_BLOCK_TABLE,
|
||||
MD_BLOCK_THEAD,
|
||||
MD_BLOCK_TBODY,
|
||||
MD_BLOCK_TR,
|
||||
MD_BLOCK_TH,
|
||||
MD_BLOCK_TD
|
||||
} MD_BLOCKTYPE;
|
||||
|
||||
/* Span represents an in-line piece of a document which should be rendered with
|
||||
* the same font, color and other attributes. A sequence of spans forms a block
|
||||
* like paragraph or list item. */
|
||||
typedef enum MD_SPANTYPE {
|
||||
/* <em>...</em> */
|
||||
MD_SPAN_EM,
|
||||
|
||||
/* <strong>...</strong> */
|
||||
MD_SPAN_STRONG,
|
||||
|
||||
/* <a href="xxx">...</a>
|
||||
* Detail: Structure MD_SPAN_A_DETAIL. */
|
||||
MD_SPAN_A,
|
||||
|
||||
/* <img src="xxx">...</a>
|
||||
* Detail: Structure MD_SPAN_IMG_DETAIL.
|
||||
* Note: Image text can contain nested spans and even nested images.
|
||||
* If rendered into ALT attribute of HTML <IMG> tag, it's responsibility
|
||||
* of the parser to deal with it.
|
||||
*/
|
||||
MD_SPAN_IMG,
|
||||
|
||||
/* <code>...</code> */
|
||||
MD_SPAN_CODE,
|
||||
|
||||
/* <del>...</del>
|
||||
* Note: Recognized only when MD_FLAG_STRIKETHROUGH is enabled.
|
||||
*/
|
||||
MD_SPAN_DEL,
|
||||
|
||||
/* For recognizing inline ($) and display ($$) equations
|
||||
* Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled.
|
||||
*/
|
||||
MD_SPAN_LATEXMATH,
|
||||
MD_SPAN_LATEXMATH_DISPLAY,
|
||||
|
||||
/* Wiki links
|
||||
* Note: Recognized only when MD_FLAG_WIKILINKS is enabled.
|
||||
*/
|
||||
MD_SPAN_WIKILINK,
|
||||
|
||||
/* <u>...</u>
|
||||
* Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */
|
||||
MD_SPAN_U
|
||||
} MD_SPANTYPE;
|
||||
|
||||
/* Text is the actual textual contents of span. */
|
||||
typedef enum MD_TEXTTYPE {
|
||||
/* Normal text. */
|
||||
MD_TEXT_NORMAL = 0,
|
||||
|
||||
/* NULL character. CommonMark requires replacing NULL character with
|
||||
* the replacement char U+FFFD, so this allows caller to do that easily. */
|
||||
MD_TEXT_NULLCHAR,
|
||||
|
||||
/* Line breaks.
|
||||
* Note these are not sent from blocks with verbatim output (MD_BLOCK_CODE
|
||||
* or MD_BLOCK_HTML). In such cases, '\n' is part of the text itself. */
|
||||
MD_TEXT_BR, /* <br> (hard break) */
|
||||
MD_TEXT_SOFTBR, /* '\n' in source text where it is not semantically meaningful (soft break) */
|
||||
|
||||
/* Entity.
|
||||
* (a) Named entity, e.g.
|
||||
* (Note MD4C does not have a list of known entities.
|
||||
* Anything matching the regexp /&[A-Za-z][A-Za-z0-9]{1,47};/ is
|
||||
* treated as a named entity.)
|
||||
* (b) Numerical entity, e.g. Ӓ
|
||||
* (c) Hexadecimal entity, e.g. ካ
|
||||
*
|
||||
* As MD4C is mostly encoding agnostic, application gets the verbatim
|
||||
* entity text into the MD_PARSER::text_callback(). */
|
||||
MD_TEXT_ENTITY,
|
||||
|
||||
/* Text in a code block (inside MD_BLOCK_CODE) or inlined code (`code`).
|
||||
* If it is inside MD_BLOCK_CODE, it includes spaces for indentation and
|
||||
* '\n' for new lines. MD_TEXT_BR and MD_TEXT_SOFTBR are not sent for this
|
||||
* kind of text. */
|
||||
MD_TEXT_CODE,
|
||||
|
||||
/* Text is a raw HTML. If it is contents of a raw HTML block (i.e. not
|
||||
* an inline raw HTML), then MD_TEXT_BR and MD_TEXT_SOFTBR are not used.
|
||||
* The text contains verbatim '\n' for the new lines. */
|
||||
MD_TEXT_HTML,
|
||||
|
||||
/* Text is inside an equation. This is processed the same way as inlined code
|
||||
* spans (`code`). */
|
||||
MD_TEXT_LATEXMATH
|
||||
} MD_TEXTTYPE;
|
||||
|
||||
|
||||
/* Alignment enumeration. */
|
||||
typedef enum MD_ALIGN {
|
||||
MD_ALIGN_DEFAULT = 0, /* When unspecified. */
|
||||
MD_ALIGN_LEFT,
|
||||
MD_ALIGN_CENTER,
|
||||
MD_ALIGN_RIGHT
|
||||
} MD_ALIGN;
|
||||
|
||||
|
||||
/* String attribute.
|
||||
*
|
||||
* This wraps strings which are outside of a normal text flow and which are
|
||||
* propagated within various detailed structures, but which still may contain
|
||||
* string portions of different types like e.g. entities.
|
||||
*
|
||||
* So, for example, lets consider this image:
|
||||
*
|
||||
* 
|
||||
*
|
||||
* The image alt text is propagated as a normal text via the MD_PARSER::text()
|
||||
* callback. However, the image title ('foo " bar') is propagated as
|
||||
* MD_ATTRIBUTE in MD_SPAN_IMG_DETAIL::title.
|
||||
*
|
||||
* Then the attribute MD_SPAN_IMG_DETAIL::title shall provide the following:
|
||||
* -- [0]: "foo " (substr_types[0] == MD_TEXT_NORMAL; substr_offsets[0] == 0)
|
||||
* -- [1]: """ (substr_types[1] == MD_TEXT_ENTITY; substr_offsets[1] == 4)
|
||||
* -- [2]: " bar" (substr_types[2] == MD_TEXT_NORMAL; substr_offsets[2] == 10)
|
||||
* -- [3]: (n/a) (n/a ; substr_offsets[3] == 14)
|
||||
*
|
||||
* Note that these invariants are always guaranteed:
|
||||
* -- substr_offsets[0] == 0
|
||||
* -- substr_offsets[LAST+1] == size
|
||||
* -- Currently, only MD_TEXT_NORMAL, MD_TEXT_ENTITY, MD_TEXT_NULLCHAR
|
||||
* substrings can appear. This could change only of the specification
|
||||
* changes.
|
||||
*/
|
||||
typedef struct MD_ATTRIBUTE {
|
||||
const MD_CHAR* text;
|
||||
MD_SIZE size;
|
||||
const MD_TEXTTYPE* substr_types;
|
||||
const MD_OFFSET* substr_offsets;
|
||||
} MD_ATTRIBUTE;
|
||||
|
||||
|
||||
/* Detailed info for MD_BLOCK_UL. */
|
||||
typedef struct MD_BLOCK_UL_DETAIL {
|
||||
int is_tight; /* Non-zero if tight list, zero if loose. */
|
||||
MD_CHAR mark; /* Item bullet character in MarkDown source of the list, e.g. '-', '+', '*'. */
|
||||
} MD_BLOCK_UL_DETAIL;
|
||||
|
||||
/* Detailed info for MD_BLOCK_OL. */
|
||||
typedef struct MD_BLOCK_OL_DETAIL {
|
||||
unsigned start; /* Start index of the ordered list. */
|
||||
int is_tight; /* Non-zero if tight list, zero if loose. */
|
||||
MD_CHAR mark_delimiter; /* Character delimiting the item marks in MarkDown source, e.g. '.' or ')' */
|
||||
} MD_BLOCK_OL_DETAIL;
|
||||
|
||||
/* Detailed info for MD_BLOCK_LI. */
|
||||
typedef struct MD_BLOCK_LI_DETAIL {
|
||||
int is_task; /* Can be non-zero only with MD_FLAG_TASKLISTS */
|
||||
MD_CHAR task_mark; /* If is_task, then one of 'x', 'X' or ' '. Undefined otherwise. */
|
||||
MD_OFFSET task_mark_offset; /* If is_task, then offset in the input of the char between '[' and ']'. */
|
||||
} MD_BLOCK_LI_DETAIL;
|
||||
|
||||
/* Detailed info for MD_BLOCK_H. */
|
||||
typedef struct MD_BLOCK_H_DETAIL {
|
||||
unsigned level; /* Header level (1 - 6) */
|
||||
} MD_BLOCK_H_DETAIL;
|
||||
|
||||
/* Detailed info for MD_BLOCK_CODE. */
|
||||
typedef struct MD_BLOCK_CODE_DETAIL {
|
||||
MD_ATTRIBUTE info;
|
||||
MD_ATTRIBUTE lang;
|
||||
MD_CHAR fence_char; /* The character used for fenced code block; or zero for indented code block. */
|
||||
} MD_BLOCK_CODE_DETAIL;
|
||||
|
||||
/* Detailed info for MD_BLOCK_TABLE. */
|
||||
typedef struct MD_BLOCK_TABLE_DETAIL {
|
||||
unsigned col_count; /* Count of columns in the table. */
|
||||
unsigned head_row_count; /* Count of rows in the table header (currently always 1) */
|
||||
unsigned body_row_count; /* Count of rows in the table body */
|
||||
} MD_BLOCK_TABLE_DETAIL;
|
||||
|
||||
/* Detailed info for MD_BLOCK_TH and MD_BLOCK_TD. */
|
||||
typedef struct MD_BLOCK_TD_DETAIL {
|
||||
MD_ALIGN align;
|
||||
} MD_BLOCK_TD_DETAIL;
|
||||
|
||||
/* Detailed info for MD_SPAN_A. */
|
||||
typedef struct MD_SPAN_A_DETAIL {
|
||||
MD_ATTRIBUTE href;
|
||||
MD_ATTRIBUTE title;
|
||||
int is_autolink; /* nonzero if this is an autolink */
|
||||
} MD_SPAN_A_DETAIL;
|
||||
|
||||
/* Detailed info for MD_SPAN_IMG. */
|
||||
typedef struct MD_SPAN_IMG_DETAIL {
|
||||
MD_ATTRIBUTE src;
|
||||
MD_ATTRIBUTE title;
|
||||
} MD_SPAN_IMG_DETAIL;
|
||||
|
||||
/* Detailed info for MD_SPAN_WIKILINK. */
|
||||
typedef struct MD_SPAN_WIKILINK {
|
||||
MD_ATTRIBUTE target;
|
||||
} MD_SPAN_WIKILINK_DETAIL;
|
||||
|
||||
/* Flags specifying extensions/deviations from CommonMark specification.
|
||||
*
|
||||
* By default (when MD_PARSER::flags == 0), we follow CommonMark specification.
|
||||
* The following flags may allow some extensions or deviations from it.
|
||||
*/
|
||||
#define MD_FLAG_COLLAPSEWHITESPACE 0x0001 /* In MD_TEXT_NORMAL, collapse non-trivial whitespace into single ' ' */
|
||||
#define MD_FLAG_PERMISSIVEATXHEADERS 0x0002 /* Do not require space in ATX headers ( ###header ) */
|
||||
#define MD_FLAG_PERMISSIVEURLAUTOLINKS 0x0004 /* Recognize URLs as autolinks even without '<', '>' */
|
||||
#define MD_FLAG_PERMISSIVEEMAILAUTOLINKS 0x0008 /* Recognize e-mails as autolinks even without '<', '>' and 'mailto:' */
|
||||
#define MD_FLAG_NOINDENTEDCODEBLOCKS 0x0010 /* Disable indented code blocks. (Only fenced code works.) */
|
||||
#define MD_FLAG_NOHTMLBLOCKS 0x0020 /* Disable raw HTML blocks. */
|
||||
#define MD_FLAG_NOHTMLSPANS 0x0040 /* Disable raw HTML (inline). */
|
||||
#define MD_FLAG_TABLES 0x0100 /* Enable tables extension. */
|
||||
#define MD_FLAG_STRIKETHROUGH 0x0200 /* Enable strikethrough extension. */
|
||||
#define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */
|
||||
#define MD_FLAG_TASKLISTS 0x0800 /* Enable task list extension. */
|
||||
#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */
|
||||
#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */
|
||||
#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */
|
||||
#define MD_FLAG_HARD_SOFT_BREAKS 0x8000 /* Force all soft breaks to act as hard breaks. */
|
||||
|
||||
#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS)
|
||||
#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS)
|
||||
|
||||
/* Convenient sets of flags corresponding to well-known Markdown dialects.
|
||||
*
|
||||
* Note we may only support subset of features of the referred dialect.
|
||||
* The constant just enables those extensions which bring us as close as
|
||||
* possible given what features we implement.
|
||||
*
|
||||
* ABI compatibility note: Meaning of these can change in time as new
|
||||
* extensions, bringing the dialect closer to the original, are implemented.
|
||||
*/
|
||||
#define MD_DIALECT_COMMONMARK 0
|
||||
#define MD_DIALECT_GITHUB (MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_TABLES | MD_FLAG_STRIKETHROUGH | MD_FLAG_TASKLISTS)
|
||||
|
||||
/* Parser structure.
|
||||
*/
|
||||
typedef struct MD_PARSER {
|
||||
/* Reserved. Set to zero.
|
||||
*/
|
||||
unsigned abi_version;
|
||||
|
||||
/* Dialect options. Bitmask of MD_FLAG_xxxx values.
|
||||
*/
|
||||
unsigned flags;
|
||||
|
||||
/* Caller-provided rendering callbacks.
|
||||
*
|
||||
* For some block/span types, more detailed information is provided in a
|
||||
* type-specific structure pointed by the argument 'detail'.
|
||||
*
|
||||
* The last argument of all callbacks, 'userdata', is just propagated from
|
||||
* md_parse() and is available for any use by the application.
|
||||
*
|
||||
* Note any strings provided to the callbacks as their arguments or as
|
||||
* members of any detail structure are generally not zero-terminated.
|
||||
* Application has to take the respective size information into account.
|
||||
*
|
||||
* Any rendering callback may abort further parsing of the document by
|
||||
* returning non-zero.
|
||||
*/
|
||||
int (*enter_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
|
||||
int (*leave_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
|
||||
|
||||
int (*enter_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
|
||||
int (*leave_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/);
|
||||
|
||||
int (*text)(MD_TEXTTYPE /*type*/, const MD_CHAR* /*text*/, MD_SIZE /*size*/, void* /*userdata*/);
|
||||
|
||||
/* Debug callback. Optional (may be NULL).
|
||||
*
|
||||
* If provided and something goes wrong, this function gets called.
|
||||
* This is intended for debugging and problem diagnosis for developers;
|
||||
* it is not intended to provide any errors suitable for displaying to an
|
||||
* end user.
|
||||
*/
|
||||
void (*debug_log)(const char* /*msg*/, void* /*userdata*/);
|
||||
|
||||
/* Reserved. Set to NULL.
|
||||
*/
|
||||
void (*syntax)(void);
|
||||
} MD_PARSER;
|
||||
|
||||
|
||||
/* For backward compatibility. Do not use in new code.
|
||||
*/
|
||||
typedef MD_PARSER MD_RENDERER;
|
||||
|
||||
|
||||
/* Parse the Markdown document stored in the string 'text' of size 'size'.
|
||||
* The parser provides callbacks to be called during the parsing so the
|
||||
* caller can render the document on the screen or convert the Markdown
|
||||
* to another format.
|
||||
*
|
||||
* Zero is returned on success. If a runtime error occurs (e.g. a memory
|
||||
* fails), -1 is returned. If the processing is aborted due any callback
|
||||
* returning non-zero, the return value of the callback is returned.
|
||||
*/
|
||||
int md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
||||
#endif /* MD4C_H */
|
||||
78
scratch/ScratchIslandApp/SampleApp/CodeBlock.cpp
Normal file
78
scratch/ScratchIslandApp/SampleApp/CodeBlock.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "CodeBlock.h"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
#include "CodeBlock.g.cpp"
|
||||
#include "RequestRunCommandsArgs.g.cpp"
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
namespace WUX = Windows::UI::Xaml;
|
||||
using IInspectable = Windows::Foundation::IInspectable;
|
||||
}
|
||||
|
||||
namespace winrt::SampleApp::implementation
|
||||
{
|
||||
CodeBlock::CodeBlock(const winrt::hstring& initialCommandlines) :
|
||||
_providedCommandlines{ initialCommandlines }
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!_providedCommandlines.empty())
|
||||
{
|
||||
WUX::Controls::TextBlock b{};
|
||||
b.Text(_providedCommandlines);
|
||||
b.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); // TODO! get the Style from the control's resources
|
||||
|
||||
CommandLines().Children().Append(b);
|
||||
}
|
||||
}
|
||||
void CodeBlock::_playPressed(const Windows::Foundation::IInspectable&,
|
||||
const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
|
||||
{
|
||||
_block = nullptr;
|
||||
OutputBlockContainer().Children().Clear();
|
||||
|
||||
auto args = winrt::make_self<RequestRunCommandsArgs>(Commandlines());
|
||||
RequestRunCommands.raise(*this, *args);
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Control::NotebookBlock CodeBlock::OutputBlock()
|
||||
{
|
||||
return _block;
|
||||
}
|
||||
void CodeBlock::OutputBlock(const winrt::Microsoft::Terminal::Control::NotebookBlock& block)
|
||||
{
|
||||
_block = block;
|
||||
_block.StateChanged({ get_weak(), &CodeBlock::_blockStateChanged });
|
||||
OutputBlockContainer().Children().Append(_block.Control());
|
||||
OutputBlockContainer().Visibility(WUX::Visibility::Visible);
|
||||
}
|
||||
void CodeBlock::_blockStateChanged(const winrt::Microsoft::Terminal::Control::NotebookBlock& sender,
|
||||
const Windows::Foundation::IInspectable&)
|
||||
{
|
||||
switch (sender.State())
|
||||
{
|
||||
case winrt::Microsoft::Terminal::Control::BlockState::Default:
|
||||
{
|
||||
WUX::VisualStateManager::GoToState(RunButton(), L"Ready", false);
|
||||
break;
|
||||
}
|
||||
case winrt::Microsoft::Terminal::Control::BlockState::Running:
|
||||
{
|
||||
WUX::VisualStateManager::GoToState(RunButton(), L"Running", false);
|
||||
break;
|
||||
}
|
||||
case winrt::Microsoft::Terminal::Control::BlockState::Finished:
|
||||
{
|
||||
WUX::VisualStateManager::GoToState(RunButton(), L"AlreadyRan", false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
scratch/ScratchIslandApp/SampleApp/CodeBlock.h
Normal file
47
scratch/ScratchIslandApp/SampleApp/CodeBlock.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CodeBlock.g.h"
|
||||
#include "RequestRunCommandsArgs.g.h"
|
||||
#include "../../../src/cascadia/inc/cppwinrt_utils.h"
|
||||
#include <til/hash.h>
|
||||
|
||||
namespace winrt::SampleApp::implementation
|
||||
{
|
||||
struct CodeBlock : CodeBlockT<CodeBlock>
|
||||
{
|
||||
CodeBlock(const winrt::hstring& initialCommandlines);
|
||||
|
||||
til::property<winrt::hstring> Commandlines;
|
||||
|
||||
winrt::Microsoft::Terminal::Control::NotebookBlock OutputBlock();
|
||||
void OutputBlock(const winrt::Microsoft::Terminal::Control::NotebookBlock& block);
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
til::typed_event<SampleApp::CodeBlock, RequestRunCommandsArgs> RequestRunCommands;
|
||||
|
||||
private:
|
||||
friend struct CodeBlockT<CodeBlock>; // for Xaml to bind events
|
||||
|
||||
winrt::hstring _providedCommandlines{};
|
||||
winrt::Microsoft::Terminal::Control::NotebookBlock _block{ nullptr };
|
||||
|
||||
void _playPressed(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
|
||||
void _blockStateChanged(const winrt::Microsoft::Terminal::Control::NotebookBlock& sender, const Windows::Foundation::IInspectable& e);
|
||||
};
|
||||
|
||||
struct RequestRunCommandsArgs : RequestRunCommandsArgsT<RequestRunCommandsArgs>
|
||||
{
|
||||
RequestRunCommandsArgs(const winrt::hstring& commandlines) :
|
||||
Commandlines{ commandlines } {};
|
||||
|
||||
til::property<winrt::hstring> Commandlines;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::SampleApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(CodeBlock);
|
||||
}
|
||||
22
scratch/ScratchIslandApp/SampleApp/CodeBlock.idl
Normal file
22
scratch/ScratchIslandApp/SampleApp/CodeBlock.idl
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace SampleApp
|
||||
{
|
||||
runtimeclass RequestRunCommandsArgs
|
||||
{
|
||||
String Commandlines { get;};
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass CodeBlock : Windows.UI.Xaml.Controls.UserControl,
|
||||
Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
CodeBlock(String initialCommandlines);
|
||||
|
||||
String Commandlines { get; set; };
|
||||
Microsoft.Terminal.Control.NotebookBlock OutputBlock;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<CodeBlock, RequestRunCommandsArgs> RequestRunCommands;
|
||||
};
|
||||
|
||||
}
|
||||
163
scratch/ScratchIslandApp/SampleApp/CodeBlock.xaml
Normal file
163
scratch/ScratchIslandApp/SampleApp/CodeBlock.xaml
Normal file
@@ -0,0 +1,163 @@
|
||||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
|
||||
the MIT License. See LICENSE in the project root for license information.
|
||||
-->
|
||||
<UserControl x:Class="SampleApp.CodeBlock"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)"
|
||||
xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:SampleApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
d:DesignHeight="256"
|
||||
d:DesignWidth="1024"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
|
||||
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Color x:Key="PlayButtonHoveredColor">#257f01</Color>
|
||||
<Color x:Key="PlayButtonNormalColor">#88222222</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<Color x:Key="PlayButtonHoveredColor">#257f01</Color>
|
||||
<Color x:Key="PlayButtonNormalColor">#88dddddd</Color>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
|
||||
<Style x:Key="PlayButtonTemplate"
|
||||
TargetType="Button">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="4" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="ButtonBaseElement"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{TemplateBinding Background}"
|
||||
BackgroundSizing="{TemplateBinding BackgroundSizing}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{TemplateBinding CornerRadius}">
|
||||
<Viewbox Width="20"
|
||||
Height="20">
|
||||
<Grid>
|
||||
<FontIcon x:Name="ButtonBackgroundIcon"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
Foreground="{ThemeResource PlayButtonHoveredColor}"
|
||||
Glyph=""
|
||||
Visibility="Collapsed" />
|
||||
<FontIcon x:Name="ButtonOutlineIcon"
|
||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
Foreground="{ThemeResource PlayButtonNormalColor}"
|
||||
Glyph="" />
|
||||
<muxc:ProgressRing x:Name="StatusProgress"
|
||||
IsActive="False" />
|
||||
</Grid>
|
||||
<!-- TODO! FontFamily="{ThemeResource SymbolThemeFontFamily}" -->
|
||||
</Viewbox>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
|
||||
<VisualState x:Name="Normal">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
|
||||
<VisualState x:Name="Disabled" />
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="PlayButtonStates">
|
||||
<VisualState x:Name="Ready">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Glyph" Value="" />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value="" />
|
||||
<Setter Target="StatusProgress.IsActive" Value="False" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="Running">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Glyph" Value=" " />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value=" " />
|
||||
<Setter Target="StatusProgress.IsActive" Value="True" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="AlreadyRan">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ButtonBackgroundIcon.Glyph" Value="" />
|
||||
<Setter Target="ButtonOutlineIcon.Glyph" Value="" />
|
||||
<Setter Target="StatusProgress.IsActive" Value="False" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
</Style>
|
||||
<Style x:Key="CodeBlockLineTemplate"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Cascadia Code" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button x:Name="RunButton"
|
||||
Grid.Column="0"
|
||||
Margin="0,9,0,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Top"
|
||||
Style="{StaticResource PlayButtonTemplate}"
|
||||
Tapped="_playPressed" />
|
||||
<Border Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="#f6f8fa"
|
||||
BorderBrush="#dbdbdb"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<StackPanel x:Name="CommandsAndOutput">
|
||||
<StackPanel x:Name="CommandLines"
|
||||
Padding="8">
|
||||
<TextBlock FontFamily="Cascadia Code"
|
||||
Text="{x:Bind Commandlines}" />
|
||||
</StackPanel>
|
||||
<StackPanel x:Name="OutputBlockContainer"
|
||||
Visibility="Collapsed">
|
||||
<!-- Put the TermControl here. -->
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <LibraryResources.h>
|
||||
#include "MyPage.g.cpp"
|
||||
#include "MySettings.h"
|
||||
#include "CodeBlock.h"
|
||||
#define MD4C_USE_UTF16
|
||||
#include "..\..\..\oss\md4c\md4c.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
@@ -19,6 +22,248 @@ namespace winrt
|
||||
|
||||
namespace winrt::SampleApp::implementation
|
||||
{
|
||||
|
||||
struct MyMarkdownData
|
||||
{
|
||||
WUX::Controls::StackPanel root{};
|
||||
implementation::MyPage* page{ nullptr };
|
||||
WUX::Controls::TextBlock current{ nullptr };
|
||||
WUX::Documents::Run currentRun{ nullptr };
|
||||
SampleApp::CodeBlock currentCodeBlock{ nullptr };
|
||||
};
|
||||
|
||||
int md_parser_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata)
|
||||
{
|
||||
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
|
||||
switch (type)
|
||||
{
|
||||
case MD_BLOCK_UL:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case MD_BLOCK_H:
|
||||
{
|
||||
MD_BLOCK_H_DETAIL* headerDetail = reinterpret_cast<MD_BLOCK_H_DETAIL*>(detail);
|
||||
data->current = WUX::Controls::TextBlock{};
|
||||
const auto fontSize = std::max(16u, 36u - ((headerDetail->level - 1) * 6u));
|
||||
data->current.FontSize(fontSize);
|
||||
data->current.FontWeight(Windows::UI::Text::FontWeights::Bold());
|
||||
WUX::Documents::Run run{};
|
||||
// run.Text(winrtL'#');
|
||||
|
||||
// Immediately add the header block
|
||||
data->root.Children().Append(data->current);
|
||||
|
||||
if (headerDetail->level == 1)
|
||||
{
|
||||
// <Border Height="1" BorderThickness="1" BorderBrush="Red" HorizontalAlignment="Stretch"></Border>
|
||||
WUX::Controls::Border b;
|
||||
b.Height(1);
|
||||
b.BorderThickness(WUX::ThicknessHelper::FromLengths(1, 1, 1, 1));
|
||||
b.BorderBrush(WUX::Media::SolidColorBrush(Windows::UI::Colors::Gray()));
|
||||
b.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
|
||||
data->root.Children().Append(b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MD_BLOCK_CODE:
|
||||
{
|
||||
MD_BLOCK_CODE_DETAIL* codeDetail = reinterpret_cast<MD_BLOCK_CODE_DETAIL*>(detail);
|
||||
codeDetail;
|
||||
|
||||
data->currentCodeBlock = winrt::make<implementation::CodeBlock>(L"");
|
||||
data->currentCodeBlock.Margin(WUX::ThicknessHelper::FromLengths(8, 8, 8, 8));
|
||||
data->currentCodeBlock.RequestRunCommands({ data->page, &MyPage::_handleRunCommandRequest });
|
||||
|
||||
data->root.Children().Append(data->currentCodeBlock);
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int md_parser_leave_block(MD_BLOCKTYPE type, void* /*detail*/, void* userdata)
|
||||
{
|
||||
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
|
||||
data;
|
||||
switch (type)
|
||||
{
|
||||
case MD_BLOCK_UL:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case MD_BLOCK_H:
|
||||
{
|
||||
// data->root.Children().Append(data->current);
|
||||
data->current = nullptr;
|
||||
break;
|
||||
}
|
||||
case MD_BLOCK_CODE:
|
||||
{
|
||||
// data->root.Children().Append(data->current);
|
||||
data->current = nullptr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int md_parser_enter_span(MD_SPANTYPE type, void* /*detail*/, void* userdata)
|
||||
{
|
||||
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
|
||||
data;
|
||||
|
||||
if (data->current == nullptr)
|
||||
{
|
||||
data->current = WUX::Controls::TextBlock();
|
||||
data->root.Children().Append(data->current);
|
||||
}
|
||||
if (data->currentRun == nullptr)
|
||||
{
|
||||
data->currentRun = WUX::Documents::Run();
|
||||
}
|
||||
auto currentRun = data->currentRun;
|
||||
switch (type)
|
||||
{
|
||||
case MD_SPAN_STRONG:
|
||||
{
|
||||
currentRun.FontWeight(Windows::UI::Text::FontWeights::Bold());
|
||||
break;
|
||||
}
|
||||
case MD_SPAN_EM:
|
||||
{
|
||||
currentRun.FontStyle(Windows::UI::Text::FontStyle::Italic);
|
||||
break;
|
||||
}
|
||||
case MD_SPAN_CODE:
|
||||
{
|
||||
currentRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" });
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int md_parser_leave_span(MD_SPANTYPE type, void* /*detail*/, void* userdata)
|
||||
{
|
||||
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
|
||||
switch (type)
|
||||
{
|
||||
case MD_SPAN_EM:
|
||||
case MD_SPAN_STRONG:
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
case MD_SPAN_CODE:
|
||||
{
|
||||
if (const auto& currentRun{ data->currentRun })
|
||||
{
|
||||
// data->current.Inlines().Append(currentRun);
|
||||
// data->currentRun = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int md_parser_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata)
|
||||
{
|
||||
MyMarkdownData* data = reinterpret_cast<MyMarkdownData*>(userdata);
|
||||
winrt::hstring str{ text, size };
|
||||
switch (type)
|
||||
{
|
||||
case MD_TEXT_BR:
|
||||
case MD_TEXT_SOFTBR:
|
||||
{
|
||||
if (const auto& curr{ data->current })
|
||||
{
|
||||
data->current = WUX::Controls::TextBlock();
|
||||
data->root.Children().Append(data->current);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MD_TEXT_CODE:
|
||||
{
|
||||
if (str == L"\n")
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (const auto& codeBlock{ data->currentCodeBlock })
|
||||
{
|
||||
// code in a fenced block
|
||||
auto currentText = codeBlock.Commandlines();
|
||||
auto newText = currentText.empty() ? str :
|
||||
currentText + winrt::hstring{ L"\r\n" } + str;
|
||||
codeBlock.Commandlines(newText);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// just normal `code` inline
|
||||
// data->currentRun.Text(str);
|
||||
[[fallthrough]];
|
||||
}
|
||||
}
|
||||
case MD_TEXT_NORMAL:
|
||||
default:
|
||||
{
|
||||
auto run = data->currentRun ? data->currentRun : WUX::Documents::Run{};
|
||||
run.Text(str);
|
||||
if (data->current)
|
||||
{
|
||||
data->current.Inlines().Append(run);
|
||||
}
|
||||
else
|
||||
{
|
||||
WUX::Controls::TextBlock block{};
|
||||
block.Inlines().Append(run);
|
||||
data->root.Children().Append(block);
|
||||
data->current = block;
|
||||
}
|
||||
// data->root.Children().Append(block);
|
||||
|
||||
data->currentRun = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parseMarkdown(const winrt::hstring& markdown, MyMarkdownData& data)
|
||||
{
|
||||
MD_PARSER parser{
|
||||
.abi_version = 0,
|
||||
.flags = 0,
|
||||
.enter_block = &md_parser_enter_block,
|
||||
.leave_block = &md_parser_leave_block,
|
||||
.enter_span = &md_parser_enter_span,
|
||||
.leave_span = &md_parser_leave_span,
|
||||
.text = &md_parser_text,
|
||||
};
|
||||
|
||||
const auto result = md_parse(
|
||||
markdown.c_str(),
|
||||
(unsigned)markdown.size(),
|
||||
&parser,
|
||||
&data // user data
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MyPage::MyPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -26,24 +271,77 @@ namespace winrt::SampleApp::implementation
|
||||
|
||||
void MyPage::Create()
|
||||
{
|
||||
auto settings = winrt::make_self<implementation::MySettings>();
|
||||
_filePath = FilePathInput().Text();
|
||||
_createNotebook();
|
||||
_loadMarkdown();
|
||||
}
|
||||
|
||||
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This TermControl is hosted in-proc...",
|
||||
winrt::hstring{},
|
||||
L"",
|
||||
nullptr,
|
||||
32,
|
||||
80,
|
||||
winrt::guid()) };
|
||||
void MyPage::_clearOldNotebook()
|
||||
{
|
||||
RenderedMarkdown().Children().Clear();
|
||||
_notebook = nullptr;
|
||||
}
|
||||
void MyPage::_loadMarkdown()
|
||||
{
|
||||
// Read _filePath, then parse as markdown.
|
||||
|
||||
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
|
||||
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
|
||||
TerminalConnection::ConnectionInformation connectInfo{ myClass, connectionSettings };
|
||||
const wil::unique_handle file{ CreateFileW(_filePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };
|
||||
if (!file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TerminalConnection::ITerminalConnection conn{ TerminalConnection::ConnectionInformation::CreateConnection(connectInfo) };
|
||||
Control::TermControl control{ *settings, *settings, conn };
|
||||
char buffer[32 * 1024];
|
||||
DWORD read = 0;
|
||||
for (;;)
|
||||
{
|
||||
if (!ReadFile(file.get(), &buffer[0], sizeof(buffer), &read, nullptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (read < sizeof(buffer))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// BLINDLY TREATING TEXT AS utf-8 (I THINK)
|
||||
std::string markdownContents{ buffer, read };
|
||||
winrt::hstring c = winrt::to_hstring(markdownContents);
|
||||
MyMarkdownData data;
|
||||
data.page = this;
|
||||
|
||||
InProcContent().Children().Append(control);
|
||||
const auto parseResult = parseMarkdown(c, data);
|
||||
|
||||
if (0 == parseResult)
|
||||
{
|
||||
RenderedMarkdown().Children().Append(data.root);
|
||||
}
|
||||
}
|
||||
void MyPage::_loadTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
|
||||
{
|
||||
auto p = FilePathInput().Text();
|
||||
if (p != _filePath)
|
||||
{
|
||||
_filePath = p;
|
||||
// Does the file exist? if not, bail
|
||||
const wil::unique_handle file{ CreateFileW(_filePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) };
|
||||
if (!file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// It does. Clear the old one
|
||||
_clearOldNotebook();
|
||||
_createNotebook();
|
||||
_loadMarkdown();
|
||||
}
|
||||
}
|
||||
void MyPage::_reloadTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
|
||||
{
|
||||
// Clear the old one
|
||||
_clearOldNotebook();
|
||||
_createNotebook();
|
||||
_loadMarkdown();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -55,7 +353,113 @@ namespace winrt::SampleApp::implementation
|
||||
// - the title of the focused control if there is one, else "Windows Terminal"
|
||||
hstring MyPage::Title()
|
||||
{
|
||||
return { L"Sample Application" };
|
||||
if (const auto& active{ _notebook.ActiveBlock() })
|
||||
{
|
||||
return active.Control().Title();
|
||||
}
|
||||
return { L"Terminal Notebook test" };
|
||||
}
|
||||
|
||||
void MyPage::_createNotebook()
|
||||
{
|
||||
auto settings = winrt::make_self<implementation::MySettings>();
|
||||
|
||||
settings->DefaultBackground(til::color{ 0x25, 0x25, 0x25 });
|
||||
settings->AutoMarkPrompts(true);
|
||||
settings->StartingTitle(L"Terminal Notebook test");
|
||||
auto envMap = winrt::single_threaded_map<winrt::hstring, winrt::hstring>();
|
||||
envMap.Insert(L"PROMPT", L"$e]133;D$e\\$e]133;A$e\\$e]9;9;$P$e\\$P$G$e]133;B$e\\");
|
||||
|
||||
auto connectionSettings{ TerminalConnection::ConptyConnection::CreateSettings(L"cmd.exe /k echo This a notebook connection.",
|
||||
winrt::hstring{},
|
||||
L"",
|
||||
false,
|
||||
L"",
|
||||
envMap.GetView(),
|
||||
32,
|
||||
80,
|
||||
winrt::guid(),
|
||||
winrt::guid()) };
|
||||
|
||||
// "Microsoft.Terminal.TerminalConnection.ConptyConnection"
|
||||
winrt::hstring myClass{ winrt::name_of<TerminalConnection::ConptyConnection>() };
|
||||
TerminalConnection::ConnectionInformation connectInfo{ myClass, connectionSettings };
|
||||
|
||||
TerminalConnection::ITerminalConnection conn{ TerminalConnection::ConnectionInformation::CreateConnection(connectInfo) };
|
||||
|
||||
_notebook = Control::Notebook(*settings, *settings, conn);
|
||||
}
|
||||
|
||||
void MyPage::_newBlockHandler(const Control::Notebook& /*sender*/,
|
||||
const Control::NotebookBlock& block)
|
||||
{
|
||||
_addControl(block.Control());
|
||||
}
|
||||
|
||||
void MyPage::_handleRunCommandRequest(const SampleApp::CodeBlock& sender,
|
||||
const SampleApp::RequestRunCommandsArgs& request)
|
||||
{
|
||||
auto text = request.Commandlines();
|
||||
auto targetControl = _notebook.ActiveBlock().Control();
|
||||
|
||||
sender.OutputBlock(_notebook.ActiveBlock());
|
||||
|
||||
targetControl.Height(256);
|
||||
targetControl.VerticalAlignment(WUX::VerticalAlignment::Top);
|
||||
targetControl.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
|
||||
|
||||
targetControl.Initialized([this, text](const auto&, auto&&) {
|
||||
_notebook.SendCommands(text + L"\r");
|
||||
});
|
||||
}
|
||||
|
||||
void MyPage::_scrollToElement(const WUX::UIElement& element,
|
||||
bool isVerticalScrolling,
|
||||
bool smoothScrolling)
|
||||
{
|
||||
const auto scrollViewer = _scrollViewer();
|
||||
|
||||
const auto origin = winrt::Windows::Foundation::Point{ 0, 0 };
|
||||
|
||||
const auto transform_scrollContent = element.TransformToVisual(scrollViewer.Content().try_as<WUX::UIElement>());
|
||||
const auto position_scrollContent = transform_scrollContent.TransformPoint(origin);
|
||||
|
||||
if (isVerticalScrolling)
|
||||
{
|
||||
scrollViewer.ChangeView(nullptr, position_scrollContent.Y, nullptr, !smoothScrolling);
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollViewer.ChangeView(position_scrollContent.X, nullptr, nullptr, !smoothScrolling);
|
||||
}
|
||||
}
|
||||
|
||||
void MyPage::_addControl(const Control::TermControl& control)
|
||||
{
|
||||
control.Height(256);
|
||||
control.VerticalAlignment(WUX::VerticalAlignment::Top);
|
||||
control.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
|
||||
|
||||
WUX::Controls::Grid wrapper{};
|
||||
wrapper.VerticalAlignment(WUX::VerticalAlignment::Top);
|
||||
wrapper.HorizontalAlignment(WUX::HorizontalAlignment::Stretch);
|
||||
wrapper.CornerRadius(WUX::CornerRadiusHelper::FromRadii(6, 6, 6, 6));
|
||||
wrapper.Margin(WUX::ThicknessHelper::FromLengths(0, 5, 0, 7));
|
||||
wrapper.Children().Append(control);
|
||||
|
||||
RenderedMarkdown().Children().Append(wrapper);
|
||||
|
||||
control.Focus(WUX::FocusState::Programmatic);
|
||||
|
||||
// Incredibly dumb: move off UI thread, then back on, then scroll to the
|
||||
// new control.
|
||||
_stupid(wrapper);
|
||||
}
|
||||
|
||||
winrt::fire_and_forget MyPage::_stupid(WUX::UIElement elem)
|
||||
{
|
||||
co_await winrt::resume_after(2ms); // no, resume_background is not enough to make this work.
|
||||
co_await winrt::resume_foreground(this->Dispatcher(), winrt::Windows::UI::Core::CoreDispatcherPriority::Low);
|
||||
_scrollToElement(elem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,31 @@ namespace winrt::SampleApp::implementation
|
||||
|
||||
hstring Title();
|
||||
|
||||
void _handleRunCommandRequest(const SampleApp::CodeBlock& sender,
|
||||
const SampleApp::RequestRunCommandsArgs& control);
|
||||
|
||||
private:
|
||||
friend struct MyPageT<MyPage>; // for Xaml to bind events
|
||||
|
||||
void _createNotebook();
|
||||
|
||||
void _clearOldNotebook();
|
||||
void _loadMarkdown();
|
||||
|
||||
winrt::Microsoft::Terminal::Control::Notebook _notebook{ nullptr };
|
||||
winrt::hstring _filePath{};
|
||||
|
||||
void _loadTapped(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
|
||||
void _reloadTapped(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e);
|
||||
|
||||
void _newBlockHandler(const winrt::Microsoft::Terminal::Control::Notebook& sender,
|
||||
const winrt::Microsoft::Terminal::Control::NotebookBlock& control);
|
||||
void _addControl(const winrt::Microsoft::Terminal::Control::TermControl& control);
|
||||
void _scrollToElement(const Windows::UI::Xaml::UIElement& element,
|
||||
bool isVerticalScrolling = true,
|
||||
bool smoothScrolling = true);
|
||||
|
||||
winrt::fire_and_forget _stupid(Windows::UI::Xaml::UIElement elem);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,15 +19,26 @@
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBox x:Name="GuidInput"
|
||||
Width="400"
|
||||
PlaceholderText="{}{guid here}" />
|
||||
<Button Grid.Row="0">
|
||||
Create
|
||||
</Button>
|
||||
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox x:Name="FilePathInput"
|
||||
Grid.Column="0"
|
||||
PlaceholderText="Enter a path to a markdown file..."
|
||||
Text="Z:\dev\public\OpenConsole\scratch\ScratchIslandApp\SampleApp\simple-test.md" />
|
||||
<StackPanel Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
<Button Tapped="_loadTapped">
|
||||
Load
|
||||
</Button>
|
||||
<Button Tapped="_reloadTapped">
|
||||
<FontIcon FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
Glyph="" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid x:Name="TabContent"
|
||||
Grid.Row="1"
|
||||
@@ -35,7 +46,7 @@
|
||||
VerticalAlignment="Stretch">
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="1" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
@@ -46,14 +57,22 @@
|
||||
VerticalAlignment="Stretch"
|
||||
Background="#ff0000" />
|
||||
|
||||
<Grid x:Name="OutOfProcContent"
|
||||
Grid.Column="1"
|
||||
Padding="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="#0000ff" />
|
||||
|
||||
|
||||
<ScrollViewer x:Name="_scrollViewer"
|
||||
Grid.Column="1"
|
||||
Padding="3"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="#eeeeee"
|
||||
BringIntoViewOnFocusChange="True"
|
||||
IsVerticalScrollChainingEnabled="True">
|
||||
<StackPanel x:Name="RenderedMarkdown"
|
||||
Grid.Column="1"
|
||||
Padding="16"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="#fff"
|
||||
Orientation="Vertical"
|
||||
RequestedTheme="Light" />
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -40,11 +40,18 @@
|
||||
<Page Include="MyPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="CodeBlock.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Headers ======================== -->
|
||||
<ItemGroup>
|
||||
<ClInclude Include="App.base.h" />
|
||||
<ClInclude Include="MySettings.h" />
|
||||
<ClInclude Include="CodeBlock.h">
|
||||
<DependentUpon>CodeBlock.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MyPage.h">
|
||||
<DependentUpon>MyPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
@@ -64,6 +71,10 @@
|
||||
<DependentUpon>MyPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CodeBlock.cpp">
|
||||
<DependentUpon>CodeBlock.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -75,6 +86,8 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
|
||||
<!-- <ClCompile Include="$(OpenConsoleDir)oss\md4c\md4c.c" /> -->
|
||||
|
||||
</ItemGroup>
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -89,6 +102,10 @@
|
||||
<DependentUpon>MyPage.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="CodeBlock.idl">
|
||||
<DependentUpon>CodeBlock.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
</ItemGroup>
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -103,6 +120,14 @@
|
||||
just has a bug in it.-->
|
||||
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>Warning</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- subsume fmt, one of our dependencies, into contypes. -->
|
||||
<ProjectReference Include="$(OpenConsoleDir)src\dep\md4c\md4c.vcxproj">
|
||||
<Project>{7cae5851-50d5-4934-8d5e-30361a8a40f3}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- ========================== Other References ========================= -->
|
||||
<ItemGroup>
|
||||
<!-- Manually add references to each of our dependent winmds. Mark them as
|
||||
|
||||
21
scratch/ScratchIslandApp/SampleApp/formatting-test.md
Normal file
21
scratch/ScratchIslandApp/SampleApp/formatting-test.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Formatting test
|
||||
## h2
|
||||
### h3
|
||||
#### h4
|
||||
##### h5
|
||||
|
||||
**bold**
|
||||
_italic_
|
||||
_**BOTH**_
|
||||
|
||||
`code`
|
||||
|
||||
text before `code` and after
|
||||
|
||||
```
|
||||
a fenced block of code
|
||||
```
|
||||
|
||||
> quoted text
|
||||
|
||||
code that's indented
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
|
||||
#include <winrt/Windows.UI.Xaml.Data.h>
|
||||
#include <winrt/Windows.UI.Xaml.Documents.h>
|
||||
#include <winrt/Windows.ui.xaml.media.h>
|
||||
#include <winrt/Windows.UI.Xaml.Media.Animation.h>
|
||||
#include <winrt/Windows.ui.xaml.input.h>
|
||||
@@ -68,3 +69,4 @@ TRACELOGGING_DECLARE_PROVIDER(g_hSampleAppProvider);
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
#include <til/winrt.h>
|
||||
|
||||
61
scratch/ScratchIslandApp/SampleApp/simple-test.md
Normal file
61
scratch/ScratchIslandApp/SampleApp/simple-test.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Readme
|
||||
|
||||
This is my cool project. It's got lots of commands.
|
||||
|
||||
#### Useful directories
|
||||
|
||||
Click these to `cd` the notebook to relevant locations.
|
||||
|
||||
```
|
||||
cd /d %~%
|
||||
```
|
||||
|
||||
```
|
||||
cd /d z:\dev\public\OpenConsole
|
||||
```
|
||||
|
||||
## build
|
||||
|
||||
### Setup
|
||||
|
||||
Dependencies!
|
||||
|
||||
```
|
||||
winget search "I most certainly don't exist"
|
||||
```
|
||||
|
||||
### Actual build
|
||||
|
||||
To build the thing, run the following command:
|
||||
|
||||
```cmd
|
||||
build the_thing
|
||||
```
|
||||
|
||||
## test
|
||||
|
||||
```cmd
|
||||
pwsh -c gci
|
||||
ping 8.8.8.8
|
||||
```
|
||||
|
||||
That _should_ run the tests
|
||||
|
||||
## Other helpful commmands
|
||||
|
||||
```
|
||||
git status
|
||||
```
|
||||
```
|
||||
git --no-pager diff dev/migrie/fhl/2024-spring-merge-base --stat -- . ":!oss/md4c"
|
||||
```
|
||||
```
|
||||
ping 8.8.8.8
|
||||
```
|
||||
|
||||
```
|
||||
set FOO=%FOO%+1 & echo FOO set to %FOO%
|
||||
```
|
||||
```
|
||||
echo This has been a test of the new code block objects
|
||||
```
|
||||
@@ -57,8 +57,8 @@ void SampleIslandWindow::MakeWindow() noexcept
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
1024, //CW_USEDEFAULT, // Initial width
|
||||
1024, // CW_USEDEFAULT, // Initial height
|
||||
nullptr,
|
||||
nullptr,
|
||||
wc.hInstance,
|
||||
|
||||
@@ -92,47 +92,35 @@ CharToColumnMapper::CharToColumnMapper(const wchar_t* chars, const uint16_t* cha
|
||||
|
||||
// If given a position (`offset`) inside the ROW's text, this function will return the corresponding column.
|
||||
// This function in particular returns the glyph's first column.
|
||||
til::CoordType CharToColumnMapper::GetLeadingColumnAt(ptrdiff_t offset) noexcept
|
||||
til::CoordType CharToColumnMapper::GetLeadingColumnAt(ptrdiff_t targetOffset) noexcept
|
||||
{
|
||||
offset = clamp(offset, 0, _lastCharOffset);
|
||||
targetOffset = clamp(targetOffset, 0, _lastCharOffset);
|
||||
|
||||
// This code needs to fulfill two conditions on top of the obvious (a forward/backward search):
|
||||
// A: We never want to stop on a column that is marked with CharOffsetsTrailer (= "GetLeadingColumn").
|
||||
// B: With these parameters we always want to stop at currentOffset=4:
|
||||
// _charOffsets={4, 6}
|
||||
// currentOffset=4 *OR* 6
|
||||
// targetOffset=5
|
||||
// This is because we're being asked for a "LeadingColumn", while the caller gave us the offset of a
|
||||
// trailing surrogate pair or similar. Returning the column of the leading half is the correct choice.
|
||||
|
||||
auto col = _currentColumn;
|
||||
const auto currentOffset = _charOffsets[col];
|
||||
auto currentOffset = _charOffsets[col];
|
||||
|
||||
// Goal: Move the _currentColumn cursor to a cell which contains the given target offset.
|
||||
// Depending on where the target offset is we have to either search forward or backward.
|
||||
if (offset < currentOffset)
|
||||
// A plain forward-search until we find our targetOffset.
|
||||
// This loop may iterate too far and thus violate our example in condition B, however...
|
||||
while (targetOffset > (currentOffset & CharOffsetsMask))
|
||||
{
|
||||
// Backward search.
|
||||
// Goal: Find the first preceding column where the offset is <= the target offset. This results in the first
|
||||
// cell that contains our target offset, even if that offset is in the middle of a long grapheme.
|
||||
//
|
||||
// We abuse the fact that the trailing half of wide glyphs is marked with CharOffsetsTrailer to our advantage.
|
||||
// Since they're >0x8000, the `offset < _charOffsets[col]` check will always be true and ensure we iterate over them.
|
||||
//
|
||||
// Since _charOffsets cannot contain negative values and because offset has been
|
||||
// clamped to be positive we naturally exit when reaching the first column.
|
||||
for (; offset < _charOffsets[col - 1]; --col)
|
||||
{
|
||||
}
|
||||
currentOffset = _charOffsets[++col];
|
||||
}
|
||||
else if (offset > currentOffset)
|
||||
// This backward-search is not just a counter-part to the above, but simultaneously also handles conditions A and B.
|
||||
// It abuses the fact that columns marked with CharOffsetsTrailer are >0x8000 and targetOffset is always <0x8000.
|
||||
// This means we skip all "trailer" columns when iterating backwards, and only stop on a non-trailer (= condition A).
|
||||
// Condition B is fixed simply because we iterate backwards after the forward-search (in that exact order).
|
||||
while (targetOffset < currentOffset)
|
||||
{
|
||||
// Forward search.
|
||||
// Goal: Find the first subsequent column where the offset is > the target offset.
|
||||
// We stop 1 column before that however so that the next loop works correctly.
|
||||
// It's the inverse of the loop above.
|
||||
//
|
||||
// Since offset has been clamped to be at most 1 less than the maximum
|
||||
// _charOffsets value the loop naturally exits before hitting the end.
|
||||
for (; offset >= (_charOffsets[col + 1] & CharOffsetsMask); ++col)
|
||||
{
|
||||
}
|
||||
// Now that we found the cell that definitely includes this char offset,
|
||||
// we have to iterate back to the cell's starting column.
|
||||
for (; WI_IsFlagSet(_charOffsets[col], CharOffsetsTrailer); --col)
|
||||
{
|
||||
}
|
||||
currentOffset = _charOffsets[--col];
|
||||
}
|
||||
|
||||
_currentColumn = col;
|
||||
@@ -404,6 +392,18 @@ til::CoordType ROW::AdjustToGlyphStart(til::CoordType column) const noexcept
|
||||
return _adjustBackward(_clampedColumn(column));
|
||||
}
|
||||
|
||||
// Returns the (exclusive) ending column of the glyph at the given column.
|
||||
// In other words, if you have 3 wide glyphs
|
||||
// AA BB CC
|
||||
// 01 23 45 <-- column
|
||||
// Examples:
|
||||
// - `AdjustToGlyphEnd(4)` returns 6.
|
||||
// - `AdjustToGlyphEnd(3)` returns 4.
|
||||
til::CoordType ROW::AdjustToGlyphEnd(til::CoordType column) const noexcept
|
||||
{
|
||||
return _adjustForward(_clampedColumnInclusive(column));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - clears char data in column in row
|
||||
// Arguments:
|
||||
@@ -939,36 +939,10 @@ uint16_t ROW::size() const noexcept
|
||||
return _columnCount;
|
||||
}
|
||||
|
||||
til::CoordType ROW::MeasureLeft() const noexcept
|
||||
// Routine Description:
|
||||
// - Retrieves the column that is one after the last non-space character in the row.
|
||||
til::CoordType ROW::GetLastNonSpaceColumn() const noexcept
|
||||
{
|
||||
const auto text = GetText();
|
||||
const auto beg = text.begin();
|
||||
const auto end = text.end();
|
||||
auto it = beg;
|
||||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (*it != L' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return gsl::narrow_cast<til::CoordType>(it - beg);
|
||||
}
|
||||
|
||||
til::CoordType ROW::MeasureRight() const noexcept
|
||||
{
|
||||
if (_wrapForced)
|
||||
{
|
||||
auto width = _columnCount;
|
||||
if (_doubleBytePadded)
|
||||
{
|
||||
width--;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
const auto text = GetText();
|
||||
const auto beg = text.begin();
|
||||
const auto end = text.end();
|
||||
@@ -988,7 +962,42 @@ til::CoordType ROW::MeasureRight() const noexcept
|
||||
//
|
||||
// An example: The row is 10 cells wide and `it` points to the second character.
|
||||
// `it - beg` would return 1, but it's possible it's actually 1 wide glyph and 8 whitespace.
|
||||
return gsl::narrow_cast<til::CoordType>(_columnCount - (end - it));
|
||||
return gsl::narrow_cast<til::CoordType>(GetReadableColumnCount() - (end - it));
|
||||
}
|
||||
|
||||
til::CoordType ROW::MeasureLeft() const noexcept
|
||||
{
|
||||
const auto text = GetText();
|
||||
const auto beg = text.begin();
|
||||
const auto end = text.end();
|
||||
auto it = beg;
|
||||
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (*it != L' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return gsl::narrow_cast<til::CoordType>(it - beg);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Retrieves the column that is one after the last valid character in the row.
|
||||
til::CoordType ROW::MeasureRight() const noexcept
|
||||
{
|
||||
if (_wrapForced)
|
||||
{
|
||||
auto width = _columnCount;
|
||||
if (_doubleBytePadded)
|
||||
{
|
||||
width--;
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
return GetLastNonSpaceColumn();
|
||||
}
|
||||
|
||||
bool ROW::ContainsText() const noexcept
|
||||
|
||||
@@ -71,7 +71,7 @@ struct CharToColumnMapper
|
||||
{
|
||||
CharToColumnMapper(const wchar_t* chars, const uint16_t* charOffsets, ptrdiff_t lastCharOffset, til::CoordType currentColumn) noexcept;
|
||||
|
||||
til::CoordType GetLeadingColumnAt(ptrdiff_t offset) noexcept;
|
||||
til::CoordType GetLeadingColumnAt(ptrdiff_t targetOffset) noexcept;
|
||||
til::CoordType GetTrailingColumnAt(ptrdiff_t offset) noexcept;
|
||||
til::CoordType GetLeadingColumnAt(const wchar_t* str) noexcept;
|
||||
til::CoordType GetTrailingColumnAt(const wchar_t* str) noexcept;
|
||||
@@ -137,6 +137,7 @@ public:
|
||||
til::CoordType NavigateToPrevious(til::CoordType column) const noexcept;
|
||||
til::CoordType NavigateToNext(til::CoordType column) const noexcept;
|
||||
til::CoordType AdjustToGlyphStart(til::CoordType column) const noexcept;
|
||||
til::CoordType AdjustToGlyphEnd(til::CoordType column) const noexcept;
|
||||
|
||||
void ClearCell(til::CoordType column);
|
||||
OutputCellIterator WriteCells(OutputCellIterator it, til::CoordType columnBegin, std::optional<bool> wrap = std::nullopt, std::optional<til::CoordType> limitRight = std::nullopt);
|
||||
@@ -151,6 +152,7 @@ public:
|
||||
TextAttribute GetAttrByColumn(til::CoordType column) const;
|
||||
std::vector<uint16_t> GetHyperlinks() const;
|
||||
uint16_t size() const noexcept;
|
||||
til::CoordType GetLastNonSpaceColumn() const noexcept;
|
||||
til::CoordType MeasureLeft() const noexcept;
|
||||
til::CoordType MeasureRight() const noexcept;
|
||||
bool ContainsText() const noexcept;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -108,7 +108,7 @@ public:
|
||||
const TextAttribute defaultAttributes,
|
||||
const UINT cursorSize,
|
||||
const bool isActiveBuffer,
|
||||
Microsoft::Console::Render::Renderer& renderer);
|
||||
Microsoft::Console::Render::Renderer* renderer);
|
||||
|
||||
TextBuffer(const TextBuffer&) = delete;
|
||||
TextBuffer(TextBuffer&&) = delete;
|
||||
@@ -194,13 +194,15 @@ public:
|
||||
til::point BufferToScreenPosition(const til::point position) const;
|
||||
|
||||
void Reset() noexcept;
|
||||
void ClearScrollback(const til::CoordType start, const til::CoordType height);
|
||||
|
||||
void ResizeTraditional(const til::size newSize);
|
||||
|
||||
void SetAsActiveBuffer(const bool isActiveBuffer) noexcept;
|
||||
bool IsActiveBuffer() const noexcept;
|
||||
|
||||
Microsoft::Console::Render::Renderer& GetRenderer() noexcept;
|
||||
Microsoft::Console::Render::Renderer* GetRenderer() noexcept;
|
||||
void ChangeRenderer(Microsoft::Console::Render::Renderer* newRenderer) { _renderer = newRenderer; };
|
||||
|
||||
void TriggerRedraw(const Microsoft::Console::Types::Viewport& viewport);
|
||||
void TriggerRedrawCursor(const til::point position);
|
||||
@@ -229,33 +231,94 @@ public:
|
||||
std::wstring GetCustomIdFromId(uint16_t id) const;
|
||||
void CopyHyperlinkMaps(const TextBuffer& OtherBuffer);
|
||||
|
||||
class TextAndColor
|
||||
{
|
||||
public:
|
||||
std::vector<std::wstring> text;
|
||||
std::vector<std::vector<COLORREF>> FgAttr;
|
||||
std::vector<std::vector<COLORREF>> BkAttr;
|
||||
};
|
||||
|
||||
size_t SpanLength(const til::point coordStart, const til::point coordEnd) const;
|
||||
|
||||
const TextAndColor GetText(const bool includeCRLF,
|
||||
const bool trimTrailingWhitespace,
|
||||
const std::vector<til::inclusive_rect>& textRects,
|
||||
std::function<std::pair<COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors = nullptr,
|
||||
const bool formatWrappedRows = false) const;
|
||||
|
||||
std::wstring GetPlainText(const til::point& start, const til::point& end) const;
|
||||
|
||||
static std::string GenHTML(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const COLORREF backgroundColor);
|
||||
struct CopyRequest
|
||||
{
|
||||
// beg and end coordinates are inclusive
|
||||
til::point beg;
|
||||
til::point end;
|
||||
|
||||
static std::string GenRTF(const TextAndColor& rows,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const COLORREF backgroundColor);
|
||||
til::CoordType minX;
|
||||
til::CoordType maxX;
|
||||
bool blockSelection = false;
|
||||
bool trimTrailingWhitespace = true;
|
||||
bool includeLineBreak = true;
|
||||
bool formatWrappedRows = false;
|
||||
|
||||
// whether beg, end coordinates are in buffer coordinates or screen coordinates
|
||||
bool bufferCoordinates = false;
|
||||
|
||||
CopyRequest() = default;
|
||||
|
||||
constexpr CopyRequest(const TextBuffer& buffer, const til::point& beg, const til::point& end, const bool blockSelection, const bool includeLineBreak, const bool trimTrailingWhitespace, const bool formatWrappedRows, const bool bufferCoordinates = false) noexcept :
|
||||
beg{ std::max(beg, til::point{ 0, 0 }) },
|
||||
end{ std::min(end, til::point{ buffer._width - 1, buffer._height - 1 }) },
|
||||
minX{ std::min(this->beg.x, this->end.x) },
|
||||
maxX{ std::max(this->beg.x, this->end.x) },
|
||||
blockSelection{ blockSelection },
|
||||
includeLineBreak{ includeLineBreak },
|
||||
trimTrailingWhitespace{ trimTrailingWhitespace },
|
||||
formatWrappedRows{ formatWrappedRows },
|
||||
bufferCoordinates{ bufferCoordinates }
|
||||
{
|
||||
}
|
||||
|
||||
static CopyRequest FromConfig(const TextBuffer& buffer,
|
||||
const til::point& beg,
|
||||
const til::point& end,
|
||||
const bool singleLine,
|
||||
const bool blockSelection,
|
||||
const bool trimBlockSelection,
|
||||
const bool bufferCoordinates = false) noexcept
|
||||
{
|
||||
return {
|
||||
buffer,
|
||||
beg,
|
||||
end,
|
||||
blockSelection,
|
||||
|
||||
/* includeLineBreak */
|
||||
// - SingleLine mode collapses all rows into one line, unless we're in
|
||||
// block selection mode.
|
||||
// - Block selection should preserve the visual structure by including
|
||||
// line breaks on all rows (together with `formatWrappedRows`).
|
||||
// (Selects like a box, pastes like a box)
|
||||
!singleLine || blockSelection,
|
||||
|
||||
/* trimTrailingWhitespace */
|
||||
// Trim trailing whitespace if we're not in single line mode and — either
|
||||
// we're not in block selection mode or, we're in block selection mode and
|
||||
// trimming is allowed.
|
||||
!singleLine && (!blockSelection || trimBlockSelection),
|
||||
|
||||
/* formatWrappedRows */
|
||||
// In block selection, we should apply formatting to wrapped rows as well.
|
||||
// (Otherwise, they're only applied to non-wrapped rows.)
|
||||
blockSelection,
|
||||
|
||||
bufferCoordinates
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
std::wstring GetPlainText(const CopyRequest& req) const;
|
||||
|
||||
std::string GenHTML(const CopyRequest& req,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const COLORREF backgroundColor,
|
||||
const bool isIntenseBold,
|
||||
std::function<std::tuple<COLORREF, COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors) const noexcept;
|
||||
|
||||
std::string GenRTF(const CopyRequest& req,
|
||||
const int fontHeightPoints,
|
||||
const std::wstring_view fontFaceName,
|
||||
const COLORREF backgroundColor,
|
||||
const bool isIntenseBold,
|
||||
std::function<std::tuple<COLORREF, COLORREF, COLORREF>(const TextAttribute&)> GetAttributeColors) const noexcept;
|
||||
|
||||
struct PositionInformation
|
||||
{
|
||||
@@ -303,10 +366,11 @@ private:
|
||||
til::point _GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
void _PruneHyperlinks();
|
||||
void _trimMarksOutsideBuffer();
|
||||
std::tuple<til::CoordType, til::CoordType, bool> _RowCopyHelper(const CopyRequest& req, const til::CoordType iRow, const ROW& row) const;
|
||||
|
||||
static void _AppendRTFText(std::ostringstream& contentBuilder, const std::wstring_view& text);
|
||||
static void _AppendRTFText(std::string& contentBuilder, const std::wstring_view& text);
|
||||
|
||||
Microsoft::Console::Render::Renderer& _renderer;
|
||||
Microsoft::Console::Render::Renderer* _renderer;
|
||||
|
||||
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
|
||||
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<ClCompile Include="ReflowTests.cpp" />
|
||||
<ClCompile Include="TextColorTests.cpp" />
|
||||
<ClCompile Include="TextAttributeTests.cpp" />
|
||||
<ClCompile Include="UTextAdapterTests.cpp" />
|
||||
<ClCompile Include="precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@@ -41,4 +42,4 @@
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
<Import Project="$(SolutionDir)src\common.build.tests.props" />
|
||||
<Import Project="$(SolutionDir)src\common.nugetversions.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
63
src/buffer/out/ut_textbuffer/UTextAdapterTests.cpp
Normal file
63
src/buffer/out/ut_textbuffer/UTextAdapterTests.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include "WexTestClass.h"
|
||||
#include "../textBuffer.hpp"
|
||||
#include "../../renderer/inc/DummyRenderer.hpp"
|
||||
|
||||
template<>
|
||||
class WEX::TestExecution::VerifyOutputTraits<std::vector<til::point_span>>
|
||||
{
|
||||
public:
|
||||
static WEX::Common::NoThrowString ToString(const std::vector<til::point_span>& vec)
|
||||
{
|
||||
WEX::Common::NoThrowString str;
|
||||
str.Append(L"{ ");
|
||||
for (size_t i = 0; i < vec.size(); ++i)
|
||||
{
|
||||
const auto& s = vec[i];
|
||||
if (i != 0)
|
||||
{
|
||||
str.Append(L", ");
|
||||
}
|
||||
str.AppendFormat(L"{(%d, %d), (%d, %d)}", s.start.x, s.start.y, s.end.x, s.end.y);
|
||||
}
|
||||
str.Append(L" }");
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
class UTextAdapterTests
|
||||
{
|
||||
TEST_CLASS(UTextAdapterTests);
|
||||
|
||||
TEST_METHOD(Unicode)
|
||||
{
|
||||
DummyRenderer renderer;
|
||||
TextBuffer buffer{ til::size{ 24, 1 }, TextAttribute{}, 0, false, renderer };
|
||||
|
||||
RowWriteState state{
|
||||
.text = L"abc 𝒶𝒷𝒸 abc ネコちゃん",
|
||||
};
|
||||
buffer.Write(0, TextAttribute{}, state);
|
||||
VERIFY_IS_TRUE(state.text.empty());
|
||||
|
||||
static constexpr auto s = [](til::CoordType beg, til::CoordType end) -> til::point_span {
|
||||
return { { beg, 0 }, { end, 0 } };
|
||||
};
|
||||
|
||||
auto expected = std::vector{ s(0, 2), s(8, 10) };
|
||||
auto actual = buffer.SearchText(L"abc", false);
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
|
||||
expected = std::vector{ s(5, 5) };
|
||||
actual = buffer.SearchText(L"𝒷", false);
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
|
||||
expected = std::vector{ s(12, 15) };
|
||||
actual = buffer.SearchText(L"ネコ", false);
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
};
|
||||
@@ -17,6 +17,7 @@ SOURCES = \
|
||||
ReflowTests.cpp \
|
||||
TextColorTests.cpp \
|
||||
TextAttributeTests.cpp \
|
||||
UTextAdapterTests.cpp \
|
||||
DefaultResource.rc \
|
||||
|
||||
TARGETLIBS = \
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
<TargetDeviceFamily Name="Windows.DesktopServer" MinVersion="10.0.19041.0" MaxVersionTested="10.0.22621.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
||||
@@ -1,404 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "../TerminalSettingsModel/ColorScheme.h"
|
||||
#include "../TerminalSettingsModel/CascadiaSettings.h"
|
||||
#include "../types/inc/colorTable.hpp"
|
||||
#include "JsonTestClass.h"
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace winrt::Microsoft::Terminal;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Common;
|
||||
|
||||
namespace SettingsModelLocalTests
|
||||
{
|
||||
// TODO:microsoft/terminal#3838:
|
||||
// Unfortunately, these tests _WILL NOT_ work in our CI. We're waiting for
|
||||
// an updated TAEF that will let us install framework packages when the test
|
||||
// package is deployed. Until then, these tests won't deploy in CI.
|
||||
|
||||
class ColorSchemeTests : public JsonTestClass
|
||||
{
|
||||
// Use a custom AppxManifest to ensure that we can activate winrt types
|
||||
// from our test. This property will tell taef to manually use this as
|
||||
// the AppxManifest for this test class.
|
||||
// This does not yet work for anything XAML-y. See TabTests.cpp for more
|
||||
// details on that.
|
||||
BEGIN_TEST_CLASS(ColorSchemeTests)
|
||||
TEST_CLASS_PROPERTY(L"RunAs", L"UAP")
|
||||
TEST_CLASS_PROPERTY(L"UAP:AppXManifest", L"TestHostAppXManifest.xml")
|
||||
END_TEST_CLASS()
|
||||
|
||||
TEST_METHOD(ParseSimpleColorScheme);
|
||||
TEST_METHOD(LayerColorSchemesOnArray);
|
||||
TEST_METHOD(UpdateSchemeReferences);
|
||||
|
||||
static Core::Color rgb(uint8_t r, uint8_t g, uint8_t b) noexcept
|
||||
{
|
||||
return Core::Color{ r, g, b, 255 };
|
||||
}
|
||||
};
|
||||
|
||||
void ColorSchemeTests::ParseSimpleColorScheme()
|
||||
{
|
||||
const std::string campbellScheme{ "{"
|
||||
"\"background\" : \"#0C0C0C\","
|
||||
"\"black\" : \"#0C0C0C\","
|
||||
"\"blue\" : \"#0037DA\","
|
||||
"\"brightBlack\" : \"#767676\","
|
||||
"\"brightBlue\" : \"#3B78FF\","
|
||||
"\"brightCyan\" : \"#61D6D6\","
|
||||
"\"brightGreen\" : \"#16C60C\","
|
||||
"\"brightPurple\" : \"#B4009E\","
|
||||
"\"brightRed\" : \"#E74856\","
|
||||
"\"brightWhite\" : \"#F2F2F2\","
|
||||
"\"brightYellow\" : \"#F9F1A5\","
|
||||
"\"cursorColor\" : \"#FFFFFF\","
|
||||
"\"cyan\" : \"#3A96DD\","
|
||||
"\"foreground\" : \"#F2F2F2\","
|
||||
"\"green\" : \"#13A10E\","
|
||||
"\"name\" : \"Campbell\","
|
||||
"\"purple\" : \"#881798\","
|
||||
"\"red\" : \"#C50F1F\","
|
||||
"\"selectionBackground\" : \"#131313\","
|
||||
"\"white\" : \"#CCCCCC\","
|
||||
"\"yellow\" : \"#C19C00\""
|
||||
"}" };
|
||||
|
||||
const auto schemeObject = VerifyParseSucceeded(campbellScheme);
|
||||
auto scheme = ColorScheme::FromJson(schemeObject);
|
||||
VERIFY_ARE_EQUAL(L"Campbell", scheme->Name());
|
||||
VERIFY_ARE_EQUAL(til::color(0xf2, 0xf2, 0xf2, 255), til::color{ scheme->Foreground() });
|
||||
VERIFY_ARE_EQUAL(til::color(0x0c, 0x0c, 0x0c, 255), til::color{ scheme->Background() });
|
||||
VERIFY_ARE_EQUAL(til::color(0x13, 0x13, 0x13, 255), til::color{ scheme->SelectionBackground() });
|
||||
VERIFY_ARE_EQUAL(til::color(0xFF, 0xFF, 0xFF, 255), til::color{ scheme->CursorColor() });
|
||||
|
||||
std::array<COLORREF, COLOR_TABLE_SIZE> expectedCampbellTable;
|
||||
const auto campbellSpan = std::span{ expectedCampbellTable };
|
||||
Utils::InitializeColorTable(campbellSpan);
|
||||
|
||||
for (size_t i = 0; i < expectedCampbellTable.size(); i++)
|
||||
{
|
||||
const til::color expected{ expectedCampbellTable.at(i) };
|
||||
const til::color actual{ scheme->Table().at(static_cast<uint32_t>(i)) };
|
||||
VERIFY_ARE_EQUAL(expected, actual);
|
||||
}
|
||||
|
||||
Log::Comment(L"Roundtrip Test for Color Scheme");
|
||||
auto outJson{ scheme->ToJson() };
|
||||
VERIFY_ARE_EQUAL(schemeObject, outJson);
|
||||
}
|
||||
|
||||
void ColorSchemeTests::LayerColorSchemesOnArray()
|
||||
{
|
||||
static constexpr std::string_view inboxSettings{ R"({
|
||||
"schemes": [
|
||||
{
|
||||
"background": "#0C0C0C",
|
||||
"black": "#0C0C0C",
|
||||
"blue": "#0037DA",
|
||||
"brightBlack": "#767676",
|
||||
"brightBlue": "#3B78FF",
|
||||
"brightCyan": "#61D6D6",
|
||||
"brightGreen": "#16C60C",
|
||||
"brightPurple": "#B4009E",
|
||||
"brightRed": "#E74856",
|
||||
"brightWhite": "#F2F2F2",
|
||||
"brightYellow": "#F9F1A5",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"cyan": "#3A96DD",
|
||||
"foreground": "#CCCCCC",
|
||||
"green": "#13A10E",
|
||||
"name": "Campbell",
|
||||
"purple": "#881798",
|
||||
"red": "#C50F1F",
|
||||
"selectionBackground": "#FFFFFF",
|
||||
"white": "#CCCCCC",
|
||||
"yellow": "#C19C00"
|
||||
}
|
||||
]
|
||||
})" };
|
||||
static constexpr std::string_view userSettings{ R"({
|
||||
"profiles": [
|
||||
{
|
||||
"name" : "profile0"
|
||||
}
|
||||
],
|
||||
"schemes": [
|
||||
{
|
||||
"background": "#121314",
|
||||
"black": "#121314",
|
||||
"blue": "#121314",
|
||||
"brightBlack": "#121314",
|
||||
"brightBlue": "#121314",
|
||||
"brightCyan": "#121314",
|
||||
"brightGreen": "#121314",
|
||||
"brightPurple": "#121314",
|
||||
"brightRed": "#121314",
|
||||
"brightWhite": "#121314",
|
||||
"brightYellow": "#121314",
|
||||
"cursorColor": "#121314",
|
||||
"cyan": "#121314",
|
||||
"foreground": "#121314",
|
||||
"green": "#121314",
|
||||
"name": "Campbell",
|
||||
"purple": "#121314",
|
||||
"red": "#121314",
|
||||
"selectionBackground": "#121314",
|
||||
"white": "#121314",
|
||||
"yellow": "#121314"
|
||||
},
|
||||
{
|
||||
"background": "#012456",
|
||||
"black": "#0C0C0C",
|
||||
"blue": "#0037DA",
|
||||
"brightBlack": "#767676",
|
||||
"brightBlue": "#3B78FF",
|
||||
"brightCyan": "#61D6D6",
|
||||
"brightGreen": "#16C60C",
|
||||
"brightPurple": "#B4009E",
|
||||
"brightRed": "#E74856",
|
||||
"brightWhite": "#F2F2F2",
|
||||
"brightYellow": "#F9F1A5",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"cyan": "#3A96DD",
|
||||
"foreground": "#CCCCCC",
|
||||
"green": "#13A10E",
|
||||
"name": "Campbell Powershell",
|
||||
"purple": "#881798",
|
||||
"red": "#C50F1F",
|
||||
"selectionBackground": "#FFFFFF",
|
||||
"white": "#CCCCCC",
|
||||
"yellow": "#C19C00"
|
||||
}
|
||||
]
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<CascadiaSettings>(userSettings, inboxSettings);
|
||||
|
||||
const auto colorSchemes = settings->GlobalSettings().ColorSchemes();
|
||||
VERIFY_ARE_EQUAL(2u, colorSchemes.Size());
|
||||
|
||||
const auto scheme0 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell"));
|
||||
VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Foreground());
|
||||
VERIFY_ARE_EQUAL(rgb(0x12, 0x13, 0x14), scheme0->Background());
|
||||
|
||||
const auto scheme1 = winrt::get_self<ColorScheme>(colorSchemes.Lookup(L"Campbell Powershell"));
|
||||
VERIFY_ARE_EQUAL(rgb(0xCC, 0xCC, 0xCC), scheme1->Foreground());
|
||||
VERIFY_ARE_EQUAL(rgb(0x01, 0x24, 0x56), scheme1->Background());
|
||||
}
|
||||
|
||||
void ColorSchemeTests::UpdateSchemeReferences()
|
||||
{
|
||||
static constexpr std::string_view settingsString{ R"json({
|
||||
"defaultProfile": "Inherited reference",
|
||||
"profiles": {
|
||||
"defaults": {
|
||||
"colorScheme": "Campbell"
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"name": "Explicit scheme reference",
|
||||
"colorScheme": "Campbell"
|
||||
},
|
||||
{
|
||||
"name": "Explicit reference; hidden",
|
||||
"colorScheme": "Campbell",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "Inherited reference"
|
||||
},
|
||||
{
|
||||
"name": "Different reference",
|
||||
"colorScheme": "One Half Dark"
|
||||
},
|
||||
{
|
||||
"name": "rename neither",
|
||||
"colorScheme":
|
||||
{
|
||||
"dark": "One Half Dark",
|
||||
"light": "One Half Light"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rename only light",
|
||||
"colorScheme":
|
||||
{
|
||||
"dark": "One Half Dark",
|
||||
"light": "Campbell"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rename only dark",
|
||||
"colorScheme":
|
||||
{
|
||||
"dark": "Campbell",
|
||||
"light": "One Half Light"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"schemes": [
|
||||
{
|
||||
"background": "#0C0C0C",
|
||||
"black": "#0C0C0C",
|
||||
"blue": "#0037DA",
|
||||
"brightBlack": "#767676",
|
||||
"brightBlue": "#3B78FF",
|
||||
"brightCyan": "#61D6D6",
|
||||
"brightGreen": "#16C60C",
|
||||
"brightPurple": "#B4009E",
|
||||
"brightRed": "#E74856",
|
||||
"brightWhite": "#F2F2F2",
|
||||
"brightYellow": "#F9F1A5",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"cyan": "#3A96DD",
|
||||
"foreground": "#CCCCCC",
|
||||
"green": "#13A10E",
|
||||
"name": "Campbell",
|
||||
"purple": "#881798",
|
||||
"red": "#C50F1F",
|
||||
"selectionBackground": "#FFFFFF",
|
||||
"white": "#CCCCCC",
|
||||
"yellow": "#C19C00"
|
||||
},
|
||||
{
|
||||
"background": "#0C0C0C",
|
||||
"black": "#0C0C0C",
|
||||
"blue": "#0037DA",
|
||||
"brightBlack": "#767676",
|
||||
"brightBlue": "#3B78FF",
|
||||
"brightCyan": "#61D6D6",
|
||||
"brightGreen": "#16C60C",
|
||||
"brightPurple": "#B4009E",
|
||||
"brightRed": "#E74856",
|
||||
"brightWhite": "#F2F2F2",
|
||||
"brightYellow": "#F9F1A5",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"cyan": "#3A96DD",
|
||||
"foreground": "#CCCCCC",
|
||||
"green": "#13A10E",
|
||||
"name": "Campbell (renamed)",
|
||||
"purple": "#881798",
|
||||
"red": "#C50F1F",
|
||||
"selectionBackground": "#FFFFFF",
|
||||
"white": "#CCCCCC",
|
||||
"yellow": "#C19C00"
|
||||
},
|
||||
{
|
||||
"background": "#282C34",
|
||||
"black": "#282C34",
|
||||
"blue": "#61AFEF",
|
||||
"brightBlack": "#5A6374",
|
||||
"brightBlue": "#61AFEF",
|
||||
"brightCyan": "#56B6C2",
|
||||
"brightGreen": "#98C379",
|
||||
"brightPurple": "#C678DD",
|
||||
"brightRed": "#E06C75",
|
||||
"brightWhite": "#DCDFE4",
|
||||
"brightYellow": "#E5C07B",
|
||||
"cursorColor": "#FFFFFF",
|
||||
"cyan": "#56B6C2",
|
||||
"foreground": "#DCDFE4",
|
||||
"green": "#98C379",
|
||||
"name": "One Half Dark",
|
||||
"purple": "#C678DD",
|
||||
"red": "#E06C75",
|
||||
"selectionBackground": "#FFFFFF",
|
||||
"white": "#DCDFE4",
|
||||
"yellow": "#E5C07B"
|
||||
},
|
||||
{
|
||||
"name": "One Half Light",
|
||||
"foreground": "#383A42",
|
||||
"background": "#FAFAFA",
|
||||
"cursorColor": "#4F525D",
|
||||
"black": "#383A42",
|
||||
"red": "#E45649",
|
||||
"green": "#50A14F",
|
||||
"yellow": "#C18301",
|
||||
"blue": "#0184BC",
|
||||
"purple": "#A626A4",
|
||||
"cyan": "#0997B3",
|
||||
"white": "#FAFAFA",
|
||||
"brightBlack": "#4F525D",
|
||||
"brightRed": "#DF6C75",
|
||||
"brightGreen": "#98C379",
|
||||
"brightYellow": "#E4C07A",
|
||||
"brightBlue": "#61AFEF",
|
||||
"brightPurple": "#C577DD",
|
||||
"brightCyan": "#56B5C1",
|
||||
"brightWhite": "#FFFFFF"
|
||||
}
|
||||
]
|
||||
})json" };
|
||||
|
||||
const auto settings{ winrt::make_self<CascadiaSettings>(settingsString) };
|
||||
|
||||
const auto newName{ L"Campbell (renamed)" };
|
||||
|
||||
settings->UpdateColorSchemeReferences(L"Campbell", newName);
|
||||
|
||||
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().DarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(newName, settings->ProfileDefaults().DefaultAppearance().LightColorSchemeName());
|
||||
VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasDarkColorSchemeName());
|
||||
VERIFY_IS_TRUE(settings->ProfileDefaults().DefaultAppearance().HasLightColorSchemeName());
|
||||
|
||||
const auto& profiles{ settings->AllProfiles() };
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(0) };
|
||||
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().DarkColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().LightColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(1) };
|
||||
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().DarkColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().LightColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(2) };
|
||||
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().DarkColorSchemeName());
|
||||
VERIFY_IS_FALSE(prof.DefaultAppearance().HasDarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().LightColorSchemeName());
|
||||
VERIFY_IS_FALSE(prof.DefaultAppearance().HasLightColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(3) };
|
||||
VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().DarkColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().LightColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(4) };
|
||||
VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().DarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(L"One Half Light", prof.DefaultAppearance().LightColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(5) };
|
||||
VERIFY_ARE_EQUAL(L"One Half Dark", prof.DefaultAppearance().DarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().LightColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName());
|
||||
}
|
||||
{
|
||||
const auto& prof{ profiles.GetAt(6) };
|
||||
VERIFY_ARE_EQUAL(newName, prof.DefaultAppearance().DarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(L"One Half Light", prof.DefaultAppearance().LightColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasDarkColorSchemeName());
|
||||
VERIFY_IS_TRUE(prof.DefaultAppearance().HasLightColorSchemeName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "../TerminalApp/TerminalPage.h"
|
||||
#include "../LocalTests_SettingsModel/TestUtils.h"
|
||||
#include "../UnitTests_SettingsModel/TestUtils.h"
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace WEX::Logging;
|
||||
|
||||
@@ -1326,7 +1326,7 @@ namespace TerminalAppLocalTests
|
||||
const auto& controlSettings = activeControl.Settings();
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() });
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
@@ -1344,7 +1344,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
Log::Comment(L"Color should be changed to the preview");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() });
|
||||
|
||||
// And we should have stored a function to revert the change.
|
||||
VERIFY_ARE_EQUAL(1u, page->_restorePreviewFuncs.size());
|
||||
@@ -1366,7 +1366,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
Log::Comment(L"Color should be changed");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() });
|
||||
|
||||
// After preview there should be no more restore functions to execute.
|
||||
VERIFY_ARE_EQUAL(0u, page->_restorePreviewFuncs.size());
|
||||
@@ -1394,7 +1394,7 @@ namespace TerminalAppLocalTests
|
||||
const auto& controlSettings = activeControl.Settings();
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() });
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
@@ -1412,7 +1412,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
Log::Comment(L"Color should be changed to the preview");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() });
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
@@ -1428,7 +1428,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
Log::Comment(L"Color should be the same as it originally was");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() });
|
||||
});
|
||||
Log::Comment(L"Sleep to let events propagate");
|
||||
Sleep(250);
|
||||
@@ -1450,7 +1450,7 @@ namespace TerminalAppLocalTests
|
||||
const auto& controlSettings = activeControl.Settings();
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, til::color{ controlSettings.DefaultBackground() });
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
@@ -1467,7 +1467,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
Log::Comment(L"Color should be changed to the preview");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, til::color{ controlSettings.DefaultBackground() });
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
@@ -1484,7 +1484,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
Log::Comment(L"Color should be changed to the preview");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, til::color{ controlSettings.DefaultBackground() });
|
||||
});
|
||||
|
||||
TestOnUIThread([&page]() {
|
||||
@@ -1503,7 +1503,7 @@ namespace TerminalAppLocalTests
|
||||
VERIFY_IS_NOT_NULL(controlSettings);
|
||||
|
||||
Log::Comment(L"Color should be changed");
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
|
||||
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, til::color{ controlSettings.DefaultBackground() });
|
||||
});
|
||||
Log::Comment(L"Sleep to let events propagate");
|
||||
Sleep(250);
|
||||
|
||||
@@ -133,7 +133,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<TestDll Include="$(OpenConsoleCommonOutDir)\LocalTests_TerminalApp\TerminalApp.LocalTests.dll" />
|
||||
<TestDll Include="$(OpenConsoleCommonOutDir)\LocalTests_SettingsModel\SettingsModel.LocalTests.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="AfterBuild" Inputs="@(TestDll)" Outputs="@(TestDll->'$(TargetDir)'\%(Filename)%(Extension)')">
|
||||
|
||||
@@ -56,6 +56,8 @@ Author(s):
|
||||
#include <winrt/windows.applicationmodel.core.h>
|
||||
|
||||
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
|
||||
#include <winrt/Microsoft.Terminal.Core.h>
|
||||
#include <winrt/Microsoft.Terminal.Control.h>
|
||||
#include <winrt/Microsoft.Terminal.Settings.Model.h>
|
||||
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.h>
|
||||
@@ -68,6 +70,8 @@ Author(s):
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#include "til.h"
|
||||
|
||||
#include <SafeDispatcherTimer.h>
|
||||
|
||||
// Common includes for most tests:
|
||||
#include "../../inc/conattrs.hpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
|
||||
@@ -95,8 +95,8 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows });
|
||||
peasant.RenameRequested({ this, &Monarch::_renameRequested });
|
||||
|
||||
peasant.ShowNotificationIconRequested([this](auto&&, auto&&) { _ShowNotificationIconRequestedHandlers(*this, nullptr); });
|
||||
peasant.HideNotificationIconRequested([this](auto&&, auto&&) { _HideNotificationIconRequestedHandlers(*this, nullptr); });
|
||||
peasant.ShowNotificationIconRequested([this](auto&&, auto&&) { ShowNotificationIconRequested.raise(*this, nullptr); });
|
||||
peasant.HideNotificationIconRequested([this](auto&&, auto&&) { HideNotificationIconRequested.raise(*this, nullptr); });
|
||||
peasant.QuitAllRequested({ this, &Monarch::_handleQuitAll });
|
||||
|
||||
{
|
||||
@@ -111,7 +111,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
_WindowCreatedHandlers(nullptr, nullptr);
|
||||
WindowCreated.raise(nullptr, nullptr);
|
||||
return newPeasantsId;
|
||||
}
|
||||
catch (...)
|
||||
@@ -141,7 +141,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// Let the process hosting the monarch run any needed logic before
|
||||
// closing all windows.
|
||||
auto args = winrt::make_self<implementation::QuitAllRequestedArgs>();
|
||||
_QuitAllRequestedHandlers(*this, *args);
|
||||
QuitAllRequested.raise(*this, *args);
|
||||
|
||||
if (const auto action = args->BeforeQuitAllAction())
|
||||
{
|
||||
@@ -207,7 +207,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
std::unique_lock lock{ _peasantsMutex };
|
||||
_peasants.erase(peasantId);
|
||||
}
|
||||
_WindowClosedHandlers(nullptr, nullptr);
|
||||
WindowClosed.raise(nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -650,7 +650,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
auto findWindowArgs{ winrt::make_self<Remoting::implementation::FindTargetWindowArgs>(args) };
|
||||
|
||||
// This is handled by some handler in-proc
|
||||
_FindTargetWindowRequestedHandlers(*this, *findWindowArgs);
|
||||
FindTargetWindowRequested.raise(*this, *findWindowArgs);
|
||||
|
||||
// After the event was handled, ResultTargetWindow() will be filled with
|
||||
// the parsed result.
|
||||
@@ -741,7 +741,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
result->WindowName(targetWindowName);
|
||||
result->ShouldCreateWindow(true);
|
||||
|
||||
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
RequestNewWindow.raise(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
|
||||
// If this fails, it'll be logged in the following
|
||||
// TraceLoggingWrite statement, with succeeded=false
|
||||
@@ -779,7 +779,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
result->Id(windowID);
|
||||
result->WindowName(targetWindowName);
|
||||
|
||||
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
RequestNewWindow.raise(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
|
||||
return *result;
|
||||
}
|
||||
@@ -796,7 +796,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
auto result = winrt::make_self<Remoting::implementation::ProposeCommandlineResult>(true);
|
||||
result->WindowName(targetWindowName);
|
||||
|
||||
_RequestNewWindowHandlers(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
RequestNewWindow.raise(*this, *winrt::make_self<WindowRequestedArgs>(*result, args));
|
||||
|
||||
return *result;
|
||||
}
|
||||
@@ -1115,7 +1115,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
auto request = winrt::make_self<implementation::WindowRequestedArgs>(nameIsReserved ? L"" : window,
|
||||
content,
|
||||
windowBounds);
|
||||
_RequestNewWindowHandlers(*this, *request);
|
||||
RequestNewWindow.raise(*this, *request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,14 +101,14 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
void RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex, const Windows::Foundation::IReference<Windows::Foundation::Rect>& windowBounds);
|
||||
void RequestSendContent(const Remoting::RequestReceiveContentArgs& args);
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
til::typed_event<> ShowNotificationIconRequested;
|
||||
til::typed_event<> HideNotificationIconRequested;
|
||||
til::typed_event<> WindowCreated;
|
||||
til::typed_event<> WindowClosed;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs> QuitAllRequested;
|
||||
|
||||
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs> RequestNewWindow;
|
||||
|
||||
private:
|
||||
uint64_t _ourPID;
|
||||
@@ -223,7 +223,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
// A peasant died, let the app host know that the number of
|
||||
// windows has changed.
|
||||
_WindowClosedHandlers(nullptr, nullptr);
|
||||
WindowClosed.raise(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// Raise an event with these args. The AppHost will listen for this
|
||||
// event to know when to take these args and dispatch them to a
|
||||
// currently-running window.
|
||||
_ExecuteCommandlineRequestedHandlers(*this, args);
|
||||
ExecuteCommandlineRequested.raise(*this, args);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -97,7 +97,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// by the monarch. The monarch might have died. If they have, this
|
||||
// will throw an exception. Just eat it, the election thread will
|
||||
// handle hooking up the new one.
|
||||
_WindowActivatedHandlers(*this, args);
|
||||
WindowActivated.raise(*this, args);
|
||||
successfullyNotified = true;
|
||||
}
|
||||
catch (...)
|
||||
@@ -146,7 +146,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE),
|
||||
TraceLoggingKeyword(TIL_KEYWORD_TRACE));
|
||||
|
||||
_SummonRequestedHandlers(*this, localCopy);
|
||||
SummonRequested.raise(*this, localCopy);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -161,7 +161,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
// Not worried about try/catching this. The handler is in AppHost, which
|
||||
// is in-proc for us.
|
||||
_DisplayWindowIdRequestedHandlers(*this, nullptr);
|
||||
DisplayWindowIdRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -182,7 +182,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// by the monarch. The monarch might have died. If they have, this
|
||||
// will throw an exception. Just eat it, the election thread will
|
||||
// handle hooking up the new one.
|
||||
_IdentifyWindowsRequestedHandlers(*this, nullptr);
|
||||
IdentifyWindowsRequested.raise(*this, nullptr);
|
||||
successfullyNotified = true;
|
||||
}
|
||||
catch (...)
|
||||
@@ -207,7 +207,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// by the monarch. The monarch might have died. If they have, this
|
||||
// will throw an exception. Just eat it, the election thread will
|
||||
// handle hooking up the new one.
|
||||
_RenameRequestedHandlers(*this, args);
|
||||
RenameRequested.raise(*this, args);
|
||||
if (args.Succeeded())
|
||||
{
|
||||
_WindowName = args.NewName();
|
||||
@@ -233,7 +233,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
try
|
||||
{
|
||||
_ShowNotificationIconRequestedHandlers(*this, nullptr);
|
||||
ShowNotificationIconRequested.raise(*this, nullptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -249,7 +249,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
try
|
||||
{
|
||||
_HideNotificationIconRequestedHandlers(*this, nullptr);
|
||||
HideNotificationIconRequested.raise(*this, nullptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -265,7 +265,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
try
|
||||
{
|
||||
_QuitAllRequestedHandlers(*this, nullptr);
|
||||
QuitAllRequested.raise(*this, nullptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -281,7 +281,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
try
|
||||
{
|
||||
_AttachRequestedHandlers(*this, request);
|
||||
AttachRequested.raise(*this, request);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -297,7 +297,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
try
|
||||
{
|
||||
_QuitRequestedHandlers(*this, nullptr);
|
||||
QuitRequested.raise(*this, nullptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -318,7 +318,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
hstring Peasant::GetWindowLayout()
|
||||
{
|
||||
auto args = winrt::make_self<implementation::GetWindowLayoutArgs>();
|
||||
_GetWindowLayoutRequestedHandlers(nullptr, *args);
|
||||
GetWindowLayoutRequested.raise(nullptr, *args);
|
||||
if (const auto op = args->WindowLayoutJsonAsync())
|
||||
{
|
||||
// This will fail if called on the UI thread, so the monarch should
|
||||
@@ -331,6 +331,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
void Peasant::SendContent(const Remoting::RequestReceiveContentArgs& args)
|
||||
{
|
||||
_SendContentRequestedHandlers(*this, args);
|
||||
SendContentRequested.raise(*this, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,25 +68,25 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
winrt::hstring GetWindowLayout();
|
||||
void SendContent(const winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs& args);
|
||||
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs> WindowActivated;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs> ExecuteCommandlineRequested;
|
||||
til::typed_event<> IdentifyWindowsRequested;
|
||||
til::typed_event<> DisplayWindowIdRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs> RenameRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior> SummonRequested;
|
||||
|
||||
til::typed_event<> ShowNotificationIconRequested;
|
||||
til::typed_event<> HideNotificationIconRequested;
|
||||
til::typed_event<> QuitAllRequested;
|
||||
til::typed_event<> QuitRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs> GetWindowLayoutRequested;
|
||||
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest> AttachRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs> SendContentRequested;
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, WindowName);
|
||||
WINRT_PROPERTY(winrt::hstring, ActiveTabTitle);
|
||||
|
||||
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs);
|
||||
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs);
|
||||
TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
|
||||
TYPED_EVENT(SummonRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::SummonWindowBehavior);
|
||||
|
||||
TYPED_EVENT(ShowNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(HideNotificationIconRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
|
||||
|
||||
TYPED_EVENT(AttachRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::AttachRequest);
|
||||
TYPED_EVENT(SendContentRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RequestReceiveContentArgs);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
uint64_t _ourPID;
|
||||
|
||||
@@ -89,10 +89,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// done when we become the king. This will be called both for the first
|
||||
// window, and when the current monarch dies.
|
||||
|
||||
_monarch.WindowCreated({ get_weak(), &WindowManager::_WindowCreatedHandlers });
|
||||
_monarch.WindowClosed({ get_weak(), &WindowManager::_WindowClosedHandlers });
|
||||
_monarch.WindowCreated({ get_weak(), &WindowManager::_bubbleWindowCreated });
|
||||
_monarch.WindowClosed({ get_weak(), &WindowManager::_bubbleWindowClosed });
|
||||
_monarch.FindTargetWindowRequested({ this, &WindowManager::_raiseFindTargetWindowRequested });
|
||||
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_QuitAllRequestedHandlers });
|
||||
_monarch.QuitAllRequested({ get_weak(), &WindowManager::_bubbleQuitAllRequested });
|
||||
|
||||
_monarch.RequestNewWindow({ get_weak(), &WindowManager::_raiseRequestNewWindow });
|
||||
}
|
||||
@@ -109,12 +109,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
void WindowManager::_raiseFindTargetWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args)
|
||||
{
|
||||
_FindTargetWindowRequestedHandlers(sender, args);
|
||||
FindTargetWindowRequested.raise(sender, args);
|
||||
}
|
||||
void WindowManager::_raiseRequestNewWindow(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args)
|
||||
{
|
||||
_RequestNewWindowHandlers(sender, args);
|
||||
RequestNewWindow.raise(sender, args);
|
||||
}
|
||||
|
||||
Remoting::ProposeCommandlineResult WindowManager::ProposeCommandline(const Remoting::CommandlineArgs& args, const bool isolatedMode)
|
||||
@@ -162,7 +162,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
auto findWindowArgs{ winrt::make_self<Remoting::implementation::FindTargetWindowArgs>(args) };
|
||||
|
||||
// This is handled by some handler in-proc
|
||||
_FindTargetWindowRequestedHandlers(*this, *findWindowArgs);
|
||||
FindTargetWindowRequested.raise(*this, *findWindowArgs);
|
||||
|
||||
// After the event was handled, ResultTargetWindow() will be filled with
|
||||
// the parsed result.
|
||||
@@ -356,7 +356,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
_monarch.AddPeasant(*p);
|
||||
|
||||
p->GetWindowLayoutRequested({ get_weak(), &WindowManager::_GetWindowLayoutRequestedHandlers });
|
||||
p->GetWindowLayoutRequested({ get_weak(), &WindowManager::_bubbleGetWindowLayoutRequested });
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_CreateOurPeasant",
|
||||
@@ -367,6 +367,23 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
return *p;
|
||||
}
|
||||
|
||||
void WindowManager::_bubbleGetWindowLayoutRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs& e)
|
||||
{
|
||||
GetWindowLayoutRequested.raise(s, e);
|
||||
}
|
||||
void WindowManager::_bubbleWindowCreated(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e)
|
||||
{
|
||||
WindowCreated.raise(s, e);
|
||||
}
|
||||
void WindowManager::_bubbleWindowClosed(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e)
|
||||
{
|
||||
WindowClosed.raise(s, e);
|
||||
}
|
||||
void WindowManager::_bubbleQuitAllRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& e)
|
||||
{
|
||||
QuitAllRequested.raise(s, e);
|
||||
}
|
||||
|
||||
void WindowManager::SignalClose(const Remoting::Peasant& peasant)
|
||||
{
|
||||
if (_monarch)
|
||||
|
||||
@@ -47,14 +47,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
winrt::fire_and_forget RequestMoveContent(winrt::hstring window, winrt::hstring content, uint32_t tabIndex, Windows::Foundation::IReference<Windows::Foundation::Rect> windowBounds);
|
||||
winrt::fire_and_forget RequestSendContent(Remoting::RequestReceiveContentArgs args);
|
||||
|
||||
TYPED_EVENT(FindTargetWindowRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs);
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs> FindTargetWindowRequested;
|
||||
|
||||
TYPED_EVENT(WindowCreated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(WindowClosed, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(QuitAllRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs);
|
||||
TYPED_EVENT(GetWindowLayoutRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs);
|
||||
|
||||
TYPED_EVENT(RequestNewWindow, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs);
|
||||
til::typed_event<> WindowCreated;
|
||||
til::typed_event<> WindowClosed;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs> QuitAllRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs> GetWindowLayoutRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs> RequestNewWindow;
|
||||
|
||||
private:
|
||||
DWORD _registrationHostClass{ 0 };
|
||||
@@ -70,6 +69,10 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);
|
||||
void _raiseRequestNewWindow(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::WindowRequestedArgs& args);
|
||||
void _bubbleWindowCreated(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e);
|
||||
void _bubbleWindowClosed(const winrt::Windows::Foundation::IInspectable& s, const winrt::Windows::Foundation::IInspectable& e);
|
||||
void _bubbleQuitAllRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::QuitAllRequestedArgs& e);
|
||||
void _bubbleGetWindowLayoutRequested(const winrt::Windows::Foundation::IInspectable& s, const winrt::Microsoft::Terminal::Remoting::GetWindowLayoutArgs& e);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@ namespace winrt::TerminalApp::implementation
|
||||
winrt::hstring ApplicationDisplayName();
|
||||
winrt::hstring ApplicationVersion();
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, UpdatesAvailable, _PropertyChangedHandlers, false);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, CheckingForUpdates, _PropertyChangedHandlers, false);
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, UpdatesAvailable, PropertyChanged.raise, false);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, CheckingForUpdates, PropertyChanged.raise, false);
|
||||
|
||||
private:
|
||||
friend struct AboutDialogT<AboutDialog>; // for Xaml to bind events
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "App.h"
|
||||
|
||||
#include "TerminalPage.h"
|
||||
#include "ScratchpadContent.h"
|
||||
#include "../WinRTUtils/inc/WtExeUtils.h"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
#include "Utils.h"
|
||||
@@ -117,7 +118,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_CloseRequestedHandlers(nullptr, nullptr);
|
||||
CloseRequested.raise(nullptr, nullptr);
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@@ -948,7 +949,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_HandleIdentifyWindows(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_IdentifyWindowsRequestedHandlers(*this, nullptr);
|
||||
IdentifyWindowsRequested.raise(*this, nullptr);
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@@ -977,7 +978,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
const auto newName = realArgs.Name();
|
||||
const auto request = winrt::make_self<implementation::RenameWindowRequestedArgs>(newName);
|
||||
_RenameWindowRequestedHandlers(*this, *request);
|
||||
RenameWindowRequested.raise(*this, *request);
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
@@ -1065,10 +1066,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (termControl.HasSelection())
|
||||
{
|
||||
const auto selections{ termControl.SelectedText(true) };
|
||||
|
||||
// concatenate the selection into a single line
|
||||
auto searchText = std::accumulate(selections.begin(), selections.end(), std::wstring());
|
||||
std::wstring searchText{ termControl.SelectedText(true) };
|
||||
|
||||
// make it compact by replacing consecutive whitespaces with a single space
|
||||
searchText = std::regex_replace(searchText, std::wregex(LR"(\s+)"), L" ");
|
||||
@@ -1150,7 +1148,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void TerminalPage::_HandleOpenSystemMenu(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
_OpenSystemMenuHandlers(*this, nullptr);
|
||||
OpenSystemMenu.raise(*this, nullptr);
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
@@ -1404,7 +1402,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto activePane{ activeTab->GetActivePane() })
|
||||
{
|
||||
_restartPaneConnection(activePane);
|
||||
_restartPaneConnection(activePane->GetContent().try_as<TerminalApp::TerminalPaneContent>(), nullptr);
|
||||
}
|
||||
}
|
||||
args.Handled(true);
|
||||
@@ -1419,6 +1417,25 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleOpenScratchpad(const IInspectable& sender,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (Feature_ScratchpadPane::IsEnabled())
|
||||
{
|
||||
const auto& scratchPane{ winrt::make_self<ScratchpadContent>() };
|
||||
|
||||
// This is maybe a little wacky - add our key event handler to the pane
|
||||
// we made. So that we can get actions for keys that the content didn't
|
||||
// handle.
|
||||
scratchPane->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler });
|
||||
|
||||
const auto resultPane = std::make_shared<Pane>(*scratchPane);
|
||||
_SplitPane(_senderOrFocusedTab(sender), SplitDirection::Automatic, 0.5f, resultPane);
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleOpenAbout(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
|
||||
@@ -124,8 +124,7 @@ namespace winrt::TerminalApp::implementation
|
||||
return appLogic->GetSettings();
|
||||
}
|
||||
|
||||
AppLogic::AppLogic() :
|
||||
_reloadState{ std::chrono::milliseconds(100), []() { ApplicationState::SharedInstance().Reload(); } }
|
||||
AppLogic::AppLogic()
|
||||
{
|
||||
// For your own sanity, it's better to do setup outside the ctor.
|
||||
// If you do any setup in the ctor that ends up throwing an exception,
|
||||
@@ -327,10 +326,6 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_reloadSettings->Run();
|
||||
}
|
||||
else if (ApplicationState::SharedInstance().IsStatePath(modifiedBasename))
|
||||
{
|
||||
_reloadState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -428,7 +423,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_settingsLoadExceptionText,
|
||||
warnings,
|
||||
_settings);
|
||||
_SettingsChangedHandlers(*this, *ev);
|
||||
SettingsChanged.raise(*this, *ev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -457,7 +452,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_settingsLoadExceptionText,
|
||||
warnings,
|
||||
_settings);
|
||||
_SettingsChangedHandlers(*this, *ev);
|
||||
SettingsChanged.raise(*this, *ev);
|
||||
}
|
||||
|
||||
// This is a continuation of AppLogic::Create() and includes the more expensive parts.
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
TerminalApp::ParseCommandlineResult GetParseCommandlineMessage(array_view<const winrt::hstring> args);
|
||||
|
||||
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs);
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SettingsLoadEventArgs> SettingsChanged;
|
||||
|
||||
private:
|
||||
bool _isElevated{ false };
|
||||
@@ -91,7 +91,6 @@ namespace winrt::TerminalApp::implementation
|
||||
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
|
||||
|
||||
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
|
||||
til::throttled_func_trailing<> _reloadState;
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::SettingsLoadWarnings> _warnings{};
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "pch.h"
|
||||
#include "ColorHelper.h"
|
||||
#include <limits>
|
||||
|
||||
using namespace winrt::TerminalApp;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
#include <winrt/windows.ui.core.h>
|
||||
#include <winrt/Windows.UI.h>
|
||||
|
||||
namespace winrt::TerminalApp
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
auto button{ sender.as<Windows::UI::Xaml::Controls::Button>() };
|
||||
auto rectClr{ button.Background().as<Windows::UI::Xaml::Media::SolidColorBrush>() };
|
||||
_ColorSelectedHandlers(rectClr.Color());
|
||||
ColorSelected.raise(rectClr.Color());
|
||||
Hide();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void ColorPickupFlyout::ClearColorButton_Click(const IInspectable&, const Windows::UI::Xaml::RoutedEventArgs&)
|
||||
{
|
||||
_ColorClearedHandlers();
|
||||
ColorCleared.raise();
|
||||
Hide();
|
||||
}
|
||||
|
||||
@@ -80,12 +80,12 @@ namespace winrt::TerminalApp::implementation
|
||||
void ColorPickupFlyout::CustomColorButton_Click(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::RoutedEventArgs&)
|
||||
{
|
||||
auto color = customColorPicker().Color();
|
||||
_ColorSelectedHandlers(color);
|
||||
ColorSelected.raise(color);
|
||||
Hide();
|
||||
}
|
||||
|
||||
void ColorPickupFlyout::ColorPicker_ColorChanged(const Microsoft::UI::Xaml::Controls::ColorPicker&, const Microsoft::UI::Xaml::Controls::ColorChangedEventArgs& args)
|
||||
{
|
||||
_ColorSelectedHandlers(args.NewColor());
|
||||
ColorSelected.raise(args.NewColor());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace winrt::TerminalApp::implementation
|
||||
void ClearColorButton_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void ColorPicker_ColorChanged(const Microsoft::UI::Xaml::Controls::ColorPicker&, const Microsoft::UI::Xaml::Controls::ColorChangedEventArgs& args);
|
||||
|
||||
WINRT_CALLBACK(ColorCleared, TerminalApp::ColorClearedArgs);
|
||||
WINRT_CALLBACK(ColorSelected, TerminalApp::ColorSelectedArgs);
|
||||
til::event<TerminalApp::ColorClearedArgs> ColorCleared;
|
||||
til::event<TerminalApp::ColorSelectedArgs> ColorSelected;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
|
||||
{
|
||||
_PreviewActionHandlers(*this, actionPaletteItem.Command());
|
||||
PreviewAction.raise(*this, actionPaletteItem.Command());
|
||||
}
|
||||
}
|
||||
else if (_currentMode == CommandPaletteMode::CommandlineMode)
|
||||
@@ -569,7 +569,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void CommandPalette::_moveBackButtonClicked(const Windows::Foundation::IInspectable& /*sender*/,
|
||||
const Windows::UI::Xaml::RoutedEventArgs&)
|
||||
{
|
||||
_PreviewActionHandlers(*this, nullptr);
|
||||
PreviewAction.raise(*this, nullptr);
|
||||
_searchBox().Focus(FocusState::Programmatic);
|
||||
|
||||
const auto previousAction{ _nestedActionStack.GetAt(_nestedActionStack.Size() - 1) };
|
||||
@@ -714,7 +714,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// All other actions can just be dispatched.
|
||||
if (actionPaletteItem.Command().ActionAndArgs().Action() != ShortcutAction::ToggleCommandPalette)
|
||||
{
|
||||
_DispatchCommandRequestedHandlers(*this, actionPaletteItem.Command());
|
||||
DispatchCommandRequested.raise(*this, actionPaletteItem.Command());
|
||||
}
|
||||
|
||||
TraceLoggingWrite(
|
||||
@@ -768,7 +768,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto tab{ tabPaletteItem.Tab() })
|
||||
{
|
||||
_SwitchToTabRequestedHandlers(*this, tab);
|
||||
SwitchToTabRequested.raise(*this, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -796,7 +796,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (const auto commandLinePaletteItem{ filteredCommand.value().Item().try_as<winrt::TerminalApp::CommandLinePaletteItem>() })
|
||||
{
|
||||
_CommandLineExecutionRequestedHandlers(*this, commandLinePaletteItem.CommandLine());
|
||||
CommandLineExecutionRequested.raise(*this, commandLinePaletteItem.CommandLine());
|
||||
_close();
|
||||
}
|
||||
}
|
||||
@@ -1187,7 +1187,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
Visibility(Visibility::Collapsed);
|
||||
|
||||
_PreviewActionHandlers(*this, nullptr);
|
||||
PreviewAction.raise(*this, nullptr);
|
||||
|
||||
// Reset visibility in case anchor mode tab switcher just finished.
|
||||
_searchBox().Visibility(Visibility::Visible);
|
||||
|
||||
@@ -48,18 +48,18 @@ namespace winrt::TerminalApp::implementation
|
||||
void EnableTabSwitcherMode(const uint32_t startIdx, Microsoft::Terminal::Settings::Model::TabSwitcherMode tabSwitcherMode);
|
||||
void EnableTabSearchMode();
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, PrefixCharacter, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, _PropertyChangedHandlers);
|
||||
til::property_changed_event PropertyChanged;
|
||||
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::TerminalApp::TabBase> SwitchToTabRequested;
|
||||
til::typed_event<winrt::TerminalApp::CommandPalette, winrt::hstring> CommandLineExecutionRequested;
|
||||
til::typed_event<winrt::TerminalApp::CommandPalette, Microsoft::Terminal::Settings::Model::Command> DispatchCommandRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command> PreviewAction;
|
||||
|
||||
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);
|
||||
TYPED_EVENT(PreviewAction, Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, PrefixCharacter, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, PropertyChanged.raise);
|
||||
|
||||
private:
|
||||
struct winrt_object_hash
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "TabBase.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
import "HighlightedTextControl.idl";
|
||||
import "FilteredCommand.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
[default_interface] runtimeclass CommandPalette : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged, IDirectKeyListener
|
||||
[default_interface] runtimeclass CommandPalette : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged, Microsoft.Terminal.UI.IDirectKeyListener
|
||||
{
|
||||
CommandPalette();
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
AllowFocusOnInteraction="True"
|
||||
AutomationProperties.Name="{x:Bind ControlName, Mode=OneWay}"
|
||||
@@ -23,12 +23,6 @@
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<!-- 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" />
|
||||
<model:IconPathConverter x:Key="IconSourceConverter" />
|
||||
|
||||
<DataTemplate x:Key="ListItemTemplate"
|
||||
x:DataType="local:FilteredCommand">
|
||||
<ListViewItem HorizontalContentAlignment="Stretch"
|
||||
@@ -62,8 +56,7 @@
|
||||
|
||||
<!--
|
||||
The block for the key chord is only visible
|
||||
when there's actual text set as the label. See
|
||||
CommandKeyChordVisibilityConverter for details.
|
||||
when there's actual text set as the label.
|
||||
We're setting the accessibility view on the
|
||||
border and text block to Raw because otherwise,
|
||||
Narrator will read out the key chord. Problem is,
|
||||
@@ -77,7 +70,7 @@
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Background="{ThemeResource FlyoutPresenterBackground}"
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
Visibility="{x:Bind Item.KeyChordText, Mode=OneWay, Converter={StaticResource CommandKeyChordVisibilityConverter}}">
|
||||
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(Item.KeyChordText), Mode=OneWay}">
|
||||
|
||||
<TextBlock AutomationProperties.AccessibilityView="Raw"
|
||||
FontSize="12"
|
||||
@@ -113,8 +106,7 @@
|
||||
|
||||
<!--
|
||||
The block for the key chord is only visible
|
||||
when there's actual text set as the label. See
|
||||
CommandKeyChordVisibilityConverter for details.
|
||||
when there's actual text set as the label.
|
||||
We're setting the accessibility view on the
|
||||
border and text block to Raw because otherwise,
|
||||
Narrator will read out the key chord. Problem is,
|
||||
@@ -127,7 +119,7 @@
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
Visibility="{x:Bind Item.KeyChordText, Mode=OneWay, Converter={StaticResource CommandKeyChordVisibilityConverter}}">
|
||||
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(Item.KeyChordText), Mode=OneWay}">
|
||||
|
||||
<TextBlock AutomationProperties.AccessibilityView="Raw"
|
||||
FontSize="12"
|
||||
@@ -347,12 +339,12 @@
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{x:Bind PrefixCharacter, Mode=OneWay}"
|
||||
Visibility="{x:Bind PrefixCharacter, Mode=OneWay, Converter={StaticResource ParentCommandVisibilityConverter}}" />
|
||||
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(PrefixCharacter), Mode=OneWay}" />
|
||||
|
||||
<StackPanel Grid.Row="1"
|
||||
Margin="8,0,8,8"
|
||||
Orientation="Horizontal"
|
||||
Visibility="{x:Bind ParentCommandName, Mode=OneWay, Converter={StaticResource ParentCommandVisibilityConverter}}">
|
||||
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(ParentCommandName), Mode=OneWay}">
|
||||
|
||||
<Button x:Name="_parentCommandBackButton"
|
||||
x:Uid="ParentCommandBackButton"
|
||||
@@ -377,7 +369,7 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Style="{ThemeResource ParsedCommandLineBorderStyle}"
|
||||
Visibility="{x:Bind ParsedCommandLineText, Mode=OneWay, Converter={StaticResource ParsedCommandLineTextVisibilityConverter}}">
|
||||
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(ParsedCommandLineText), Mode=OneWay}">
|
||||
|
||||
<ScrollViewer MaxHeight="200"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
void TerminalOutput(const winrt::event_token& token) noexcept { _wrappedConnection.TerminalOutput(token); };
|
||||
winrt::event_token StateChanged(const TypedEventHandler<ITerminalConnection, IInspectable>& handler) { return _wrappedConnection.StateChanged(handler); };
|
||||
void StateChanged(const winrt::event_token& token) noexcept { _wrappedConnection.StateChanged(token); };
|
||||
winrt::guid SessionId() const noexcept { return {}; }
|
||||
ConnectionState State() const noexcept { return _wrappedConnection.State(); }
|
||||
|
||||
private:
|
||||
@@ -61,7 +62,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
{
|
||||
_outputRevoker = wrappedConnection.TerminalOutput(winrt::auto_revoke, { this, &DebugTapConnection::_OutputHandler });
|
||||
_stateChangedRevoker = wrappedConnection.StateChanged(winrt::auto_revoke, [this](auto&& /*s*/, auto&& /*e*/) {
|
||||
_StateChangedHandlers(*this, nullptr);
|
||||
StateChanged.raise(*this, nullptr);
|
||||
});
|
||||
_wrappedConnection = wrappedConnection;
|
||||
}
|
||||
@@ -98,6 +99,15 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
_wrappedConnection = nullptr;
|
||||
}
|
||||
|
||||
guid DebugTapConnection::SessionId() const noexcept
|
||||
{
|
||||
if (const auto c = _wrappedConnection.get())
|
||||
{
|
||||
return c.SessionId();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ConnectionState DebugTapConnection::State() const noexcept
|
||||
{
|
||||
if (auto strongConnection{ _wrappedConnection.get() })
|
||||
@@ -117,7 +127,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
{
|
||||
output.insert(++lfPos, L"\r\n");
|
||||
}
|
||||
_TerminalOutputHandlers(output);
|
||||
TerminalOutput.raise(output);
|
||||
}
|
||||
|
||||
// Called by the DebugInputTapConnection to print user input
|
||||
@@ -125,7 +135,7 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
{
|
||||
auto clean{ til::visualize_control_codes(str) };
|
||||
auto formatted{ wil::str_printf<std::wstring>(L"\x1b[91m%ls\x1b[m", clean.data()) };
|
||||
_TerminalOutputHandlers(formatted);
|
||||
TerminalOutput.raise(formatted);
|
||||
}
|
||||
|
||||
// Wire us up so that we can forward input through
|
||||
|
||||
@@ -19,13 +19,15 @@ namespace winrt::Microsoft::TerminalApp::implementation
|
||||
void WriteInput(const hstring& data);
|
||||
void Resize(uint32_t rows, uint32_t columns);
|
||||
void Close();
|
||||
|
||||
winrt::guid SessionId() const noexcept;
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState State() const noexcept;
|
||||
|
||||
void SetInputTap(const Microsoft::Terminal::TerminalConnection::ITerminalConnection& inputTap);
|
||||
|
||||
WINRT_CALLBACK(TerminalOutput, winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler);
|
||||
til::event<winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler> TerminalOutput;
|
||||
|
||||
TYPED_EVENT(StateChanged, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, winrt::Windows::Foundation::IInspectable);
|
||||
til::typed_event<winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, winrt::Windows::Foundation::IInspectable> StateChanged;
|
||||
|
||||
private:
|
||||
void _PrintInput(const hstring& data);
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "EmptyStringVisibilityConverter.h"
|
||||
#include "EmptyStringVisibilityConverter.g.cpp"
|
||||
|
||||
using namespace winrt::Windows;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Method Description:
|
||||
// - Attempt to convert something into another type. For the
|
||||
// EmptyStringVisibilityConverter, we're gonna check if `value` is a
|
||||
// string, and try and convert it into a Visibility value. If the input
|
||||
// param wasn't a string, or was the empty string, we'll return
|
||||
// Visibility::Collapsed. Otherwise, we'll return Visible.
|
||||
|
||||
// Arguments:
|
||||
// - value: the input object to attempt to convert into a Visibility.
|
||||
// Return Value:
|
||||
// - Visible if the object was a string and wasn't the empty string.
|
||||
Foundation::IInspectable EmptyStringVisibilityConverter::Convert(const Foundation::IInspectable& value,
|
||||
const Windows::UI::Xaml::Interop::TypeName& /* targetType */,
|
||||
const Foundation::IInspectable& /* parameter */,
|
||||
const hstring& /* language */)
|
||||
{
|
||||
const auto& name = winrt::unbox_value_or<hstring>(value, L"");
|
||||
return winrt::box_value(name.empty() ? Visibility::Collapsed : Visibility::Visible);
|
||||
}
|
||||
|
||||
// unused for one-way bindings
|
||||
Foundation::IInspectable EmptyStringVisibilityConverter::ConvertBack(const Foundation::IInspectable& /* value */,
|
||||
const Windows::UI::Xaml::Interop::TypeName& /* targetType */,
|
||||
const Foundation::IInspectable& /* parameter */,
|
||||
const hstring& /* language */)
|
||||
{
|
||||
throw hresult_not_implemented();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "EmptyStringVisibilityConverter.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct EmptyStringVisibilityConverter : EmptyStringVisibilityConverterT<EmptyStringVisibilityConverter>
|
||||
{
|
||||
EmptyStringVisibilityConverter() = default;
|
||||
|
||||
Windows::Foundation::IInspectable Convert(const Windows::Foundation::IInspectable& value,
|
||||
const Windows::UI::Xaml::Interop::TypeName& targetType,
|
||||
const Windows::Foundation::IInspectable& parameter,
|
||||
const hstring& language);
|
||||
|
||||
Windows::Foundation::IInspectable ConvertBack(const Windows::Foundation::IInspectable& value,
|
||||
const Windows::UI::Xaml::Interop::TypeName& targetType,
|
||||
const Windows::Foundation::IInspectable& parameter,
|
||||
const hstring& language);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(EmptyStringVisibilityConverter);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
// See https://docs.microsoft.com/en-us/windows/uwp/data-binding/data-binding-quickstart
|
||||
|
||||
// We use the default attribute to declare IValueConverter as the default
|
||||
// interface. In the listing, EmptyStringVisibilityConverter has only a
|
||||
// constructor, and no methods, so no default interface is generated for it.
|
||||
// The default attribute is optimal if you won't be adding instance members
|
||||
// to EmptyStringVisibilityConverter, because no QueryInterface will be
|
||||
// required to call the IValueConverter methods
|
||||
runtimeclass EmptyStringVisibilityConverter : [default] Windows.UI.Xaml.Data.IValueConverter
|
||||
{
|
||||
EmptyStringVisibilityConverter();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -23,11 +23,11 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
static int Compare(const winrt::TerminalApp::FilteredCommand& first, const winrt::TerminalApp::FilteredCommand& second);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::PaletteItem, Item, _PropertyChangedHandlers, nullptr);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Filter, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedName, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(int, Weight, _PropertyChangedHandlers);
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::PaletteItem, Item, PropertyChanged.raise, nullptr);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Filter, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::HighlightedText, HighlightedName, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(int, Weight, PropertyChanged.raise);
|
||||
|
||||
private:
|
||||
winrt::TerminalApp::HighlightedText _computeHighlightedName();
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace winrt::TerminalApp::implementation
|
||||
HighlightedTextSegment() = default;
|
||||
HighlightedTextSegment(const winrt::hstring& text, bool isHighlighted);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, TextSegment, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, IsHighlighted, _PropertyChangedHandlers);
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, TextSegment, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, IsHighlighted, PropertyChanged.raise);
|
||||
};
|
||||
|
||||
struct HighlightedText : HighlightedTextT<HighlightedText>
|
||||
@@ -23,8 +23,8 @@ namespace winrt::TerminalApp::implementation
|
||||
HighlightedText() = default;
|
||||
HighlightedText(const Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>& segments);
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>, Segments, _PropertyChangedHandlers);
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<winrt::TerminalApp::HighlightedTextSegment>, Segments, PropertyChanged.raise);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
// C++/winrt makes it difficult to share this idl between two projects,
|
||||
// Instead, we just pin the uuid and include it in both TermControl and App
|
||||
// If you update this one, please update the one in TerminalControl\TermControl.idl
|
||||
// If you change this interface, please update the guid.
|
||||
// If you press F7 or Alt and get a runtime error, go make sure both copies are the same.
|
||||
[uuid("0ddf4edc-3fda-4dee-97ca-a417ee3dd510")] interface IDirectKeyListener {
|
||||
Boolean OnDirectKeyEvent(UInt32 vkey, UInt8 scanCode, Boolean down);
|
||||
}
|
||||
}
|
||||
56
src/cascadia/TerminalApp/IPaneContent.idl
Normal file
56
src/cascadia/TerminalApp/IPaneContent.idl
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
|
||||
runtimeclass BellEventArgs
|
||||
{
|
||||
Boolean FlashTaskbar { get; };
|
||||
};
|
||||
|
||||
interface IPaneContent
|
||||
{
|
||||
Windows.UI.Xaml.FrameworkElement GetRoot();
|
||||
void UpdateSettings(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
|
||||
|
||||
Windows.Foundation.Size MinSize { get; };
|
||||
|
||||
String Title { get; };
|
||||
UInt64 TaskbarState { get; };
|
||||
UInt64 TaskbarProgress { get; };
|
||||
Boolean ReadOnly { get; };
|
||||
String Icon { get; };
|
||||
Windows.Foundation.IReference<Windows.UI.Color> TabColor { get; };
|
||||
Windows.UI.Xaml.Media.Brush BackgroundBrush { get; };
|
||||
|
||||
Microsoft.Terminal.Settings.Model.NewTerminalArgs GetNewTerminalArgs(Boolean asContent);
|
||||
|
||||
void Focus(Windows.UI.Xaml.FocusState reason);
|
||||
|
||||
void Close();
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, BellEventArgs> BellRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TitleChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ConnectionStateChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ReadOnlyChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FocusRequested;
|
||||
};
|
||||
|
||||
|
||||
enum PaneSnapDirection
|
||||
{
|
||||
Width,
|
||||
Height
|
||||
};
|
||||
|
||||
interface ISnappable
|
||||
{
|
||||
Single SnapDownToGrid(PaneSnapDirection direction, Single sizeToSnap);
|
||||
Windows.Foundation.Size GridSize { get; };
|
||||
};
|
||||
}
|
||||
@@ -69,18 +69,18 @@ namespace winrt::TerminalApp::implementation
|
||||
void MinMaxCloseControl::_MinimizeClick(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const RoutedEventArgs& e)
|
||||
{
|
||||
_MinimizeClickHandlers(*this, e);
|
||||
MinimizeClick.raise(*this, e);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::_MaximizeClick(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const RoutedEventArgs& e)
|
||||
{
|
||||
_MaximizeClickHandlers(*this, e);
|
||||
MaximizeClick.raise(*this, e);
|
||||
}
|
||||
void MinMaxCloseControl::_CloseClick(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const RoutedEventArgs& e)
|
||||
{
|
||||
_CloseClickHandlers(*this, e);
|
||||
CloseClick.raise(*this, e);
|
||||
}
|
||||
|
||||
void MinMaxCloseControl::SetWindowVisualState(WindowVisualState visualState)
|
||||
|
||||
@@ -28,9 +28,9 @@ namespace winrt::TerminalApp::implementation
|
||||
void _CloseClick(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
|
||||
TYPED_EVENT(MinimizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
TYPED_EVENT(MaximizeClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
TYPED_EVENT(CloseClick, TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MinimizeClick;
|
||||
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MaximizeClick;
|
||||
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> CloseClick;
|
||||
|
||||
std::shared_ptr<ThrottledFuncTrailing<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
|
||||
std::optional<CaptionButton> _lastPressedButton{ std::nullopt };
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
Controls::IconElement PaletteItem::ResolvedIcon()
|
||||
{
|
||||
const auto icon = IconPathConverter::IconWUX(Icon());
|
||||
const auto icon = Microsoft::Terminal::UI::IconPathConverter::IconWUX(Icon());
|
||||
icon.Width(16);
|
||||
icon.Height(16);
|
||||
return icon;
|
||||
|
||||
@@ -11,10 +11,10 @@ namespace winrt::TerminalApp::implementation
|
||||
public:
|
||||
Windows::UI::Xaml::Controls::IconElement ResolvedIcon();
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
til::property_changed_event PropertyChanged;
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Name, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, KeyChordText, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Name, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, KeyChordText, PropertyChanged.raise);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,19 +33,21 @@ static const int CombinedPaneBorderSize = 2 * PaneBorderSize;
|
||||
static const int AnimationDurationInMilliseconds = 200;
|
||||
static const Duration AnimationDuration = DurationHelper::FromTimeSpan(winrt::Windows::Foundation::TimeSpan(std::chrono::milliseconds(AnimationDurationInMilliseconds)));
|
||||
|
||||
Pane::Pane(const Profile& profile, const TermControl& control, const bool lastFocused) :
|
||||
_control{ control },
|
||||
_lastActive{ lastFocused },
|
||||
_profile{ profile }
|
||||
Pane::Pane(const IPaneContent& content, const bool lastFocused) :
|
||||
_content{ content },
|
||||
_lastActive{ lastFocused }
|
||||
{
|
||||
_root.Children().Append(_borderFirst);
|
||||
_borderFirst.Child(_control);
|
||||
|
||||
_setupControlEvents();
|
||||
const auto& control{ _content.GetRoot() };
|
||||
_borderFirst.Child(control);
|
||||
|
||||
// Register an event with the control to have it inform us when it gains focus.
|
||||
_gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler });
|
||||
_lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler });
|
||||
if (control)
|
||||
{
|
||||
_gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ContentGotFocusHandler });
|
||||
_lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ContentLostFocusHandler });
|
||||
}
|
||||
|
||||
// When our border is tapped, make sure to transfer focus to our control.
|
||||
// LOAD-BEARING: This will NOT work if the border's BorderBrush is set to
|
||||
@@ -102,19 +104,6 @@ Pane::Pane(std::shared_ptr<Pane> first,
|
||||
});
|
||||
}
|
||||
|
||||
void Pane::_setupControlEvents()
|
||||
{
|
||||
_controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &Pane::_ControlConnectionStateChangedHandler });
|
||||
_controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { this, &Pane::_ControlWarningBellHandler });
|
||||
_controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { this, &Pane::_CloseTerminalRequestedHandler });
|
||||
_controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { this, &Pane::_RestartTerminalRequestedHandler });
|
||||
_controlEvents._ReadOnlyChanged = _control.ReadOnlyChanged(winrt::auto_revoke, { this, &Pane::_ControlReadOnlyChangedHandler });
|
||||
}
|
||||
void Pane::_removeControlEvents()
|
||||
{
|
||||
_controlEvents = {};
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Extract the terminal settings from the current (leaf) pane's control
|
||||
// to be used to create an equivalent control
|
||||
@@ -129,55 +118,7 @@ NewTerminalArgs Pane::GetTerminalArgsForPane(const bool asContent) const
|
||||
// Leaves are the only things that have controls
|
||||
assert(_IsLeaf());
|
||||
|
||||
NewTerminalArgs args{};
|
||||
auto controlSettings = _control.Settings();
|
||||
|
||||
args.Profile(controlSettings.ProfileName());
|
||||
// If we know the user's working directory use it instead of the profile.
|
||||
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
|
||||
{
|
||||
args.StartingDirectory(dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.StartingDirectory(controlSettings.StartingDirectory());
|
||||
}
|
||||
args.TabTitle(controlSettings.StartingTitle());
|
||||
args.Commandline(controlSettings.Commandline());
|
||||
args.SuppressApplicationTitle(controlSettings.SuppressApplicationTitle());
|
||||
if (controlSettings.TabColor() || controlSettings.StartingTabColor())
|
||||
{
|
||||
til::color c;
|
||||
// StartingTabColor is prioritized over other colors
|
||||
if (const auto color = controlSettings.StartingTabColor())
|
||||
{
|
||||
c = til::color(color.Value());
|
||||
}
|
||||
else
|
||||
{
|
||||
c = til::color(controlSettings.TabColor().Value());
|
||||
}
|
||||
|
||||
args.TabColor(winrt::Windows::Foundation::IReference<winrt::Windows::UI::Color>{ static_cast<winrt::Windows::UI::Color>(c) });
|
||||
}
|
||||
|
||||
// TODO:GH#9800 - we used to be able to persist the color scheme that a
|
||||
// TermControl was initialized with, by name. With the change to having the
|
||||
// control own its own copy of its settings, this isn't possible anymore.
|
||||
//
|
||||
// We may be able to get around this by storing the Name in the Core::Scheme
|
||||
// object. That would work for schemes set by the Terminal, but not ones set
|
||||
// by VT, but that seems good enough.
|
||||
|
||||
// Only fill in the ContentId if absolutely needed. If you fill in a number
|
||||
// here (even 0), we'll serialize that number, AND treat that action as an
|
||||
// "attach existing" rather than a "create"
|
||||
if (asContent)
|
||||
{
|
||||
args.ContentId(_control.ContentId());
|
||||
}
|
||||
|
||||
return args;
|
||||
return _content.GetNewTerminalArgs(asContent);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1022,181 +963,18 @@ Pane::PaneNeighborSearch Pane::_FindPaneAndNeighbor(const std::shared_ptr<Pane>
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Called when our attached control is closed. Triggers listeners to our close
|
||||
// event, if we're a leaf pane.
|
||||
// - If this was called, and we became a parent pane (due to work on another
|
||||
// thread), this function will do nothing (allowing the control's new parent
|
||||
// to handle the event instead).
|
||||
// - Returns true if the connection state of this pane is closed.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget Pane::_ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
// - true if the connection state of this Pane is closed.
|
||||
bool Pane::IsConnectionClosed() const
|
||||
{
|
||||
auto newConnectionState = ConnectionState::Closed;
|
||||
if (const auto coreState = sender.try_as<ICoreState>())
|
||||
if (const auto& control{ GetTerminalControl() })
|
||||
{
|
||||
newConnectionState = coreState.ConnectionState();
|
||||
}
|
||||
|
||||
const auto previousConnectionState = std::exchange(_connectionState, newConnectionState);
|
||||
if (newConnectionState < ConnectionState::Closed)
|
||||
{
|
||||
// Pane doesn't care if the connection isn't entering a terminal state.
|
||||
co_return;
|
||||
}
|
||||
|
||||
const auto weakThis = weak_from_this();
|
||||
co_await wil::resume_foreground(_root.Dispatcher());
|
||||
const auto strongThis = weakThis.lock();
|
||||
if (!strongThis)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
// It's possible that this event handler started being executed, scheduled
|
||||
// on the UI thread, another child got created. So our control is
|
||||
// actually no longer _our_ control, and instead could be a descendant.
|
||||
//
|
||||
// When the control's new Pane takes ownership of the control, the new
|
||||
// parent will register its own event handler. That event handler will get
|
||||
// fired after this handler returns, and will properly cleanup state.
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
if (previousConnectionState < ConnectionState::Connected && newConnectionState >= ConnectionState::Failed)
|
||||
{
|
||||
// A failure to complete the connection (before it has _connected_) is not covered by "closeOnExit".
|
||||
// This is to prevent a misconfiguration (closeOnExit: always, startingDirectory: garbage) resulting
|
||||
// in Terminal flashing open and immediately closed.
|
||||
co_return;
|
||||
}
|
||||
|
||||
if (_profile)
|
||||
{
|
||||
if (_isDefTermSession && _profile.CloseOnExit() == CloseOnExitMode::Automatic)
|
||||
{
|
||||
// For 'automatic', we only care about the connection state if we were launched by Terminal
|
||||
// Since we were launched via defterm, ignore the connection state (i.e. we treat the
|
||||
// close on exit mode as 'always', see GH #13325 for discussion)
|
||||
Close();
|
||||
}
|
||||
|
||||
const auto mode = _profile.CloseOnExit();
|
||||
if ((mode == CloseOnExitMode::Always) ||
|
||||
((mode == CloseOnExitMode::Graceful || mode == CloseOnExitMode::Automatic) && newConnectionState == ConnectionState::Closed))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::_CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
{
|
||||
// It's possible that this event handler started being executed, then before
|
||||
// we got the lock, another thread created another child. So our control is
|
||||
// actually no longer _our_ control, and instead could be a descendant.
|
||||
//
|
||||
// When the control's new Pane takes ownership of the control, the new
|
||||
// parent will register its own event handler. That event handler will get
|
||||
// fired after this handler returns, and will properly cleanup state.
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
void Pane::_RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
{
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_RestartTerminalRequestedHandlers(shared_from_this());
|
||||
}
|
||||
|
||||
winrt::fire_and_forget Pane::_playBellSound(winrt::Windows::Foundation::Uri uri)
|
||||
{
|
||||
auto weakThis{ weak_from_this() };
|
||||
|
||||
co_await wil::resume_foreground(_root.Dispatcher());
|
||||
if (auto pane{ weakThis.lock() })
|
||||
{
|
||||
if (!_bellPlayerCreated)
|
||||
{
|
||||
// The MediaPlayer might not exist on Windows N SKU.
|
||||
try
|
||||
{
|
||||
_bellPlayerCreated = true;
|
||||
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
|
||||
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
|
||||
_bellPlayer.CommandManager().IsEnabled(false);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
if (_bellPlayer)
|
||||
{
|
||||
const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) };
|
||||
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
|
||||
_bellPlayer.Source(item);
|
||||
_bellPlayer.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Plays a warning note when triggered by the BEL control character,
|
||||
// using the sound configured for the "Critical Stop" system event.`
|
||||
// This matches the behavior of the Windows Console host.
|
||||
// - Will also flash the taskbar if the bellStyle setting for this profile
|
||||
// has the 'visual' flag set
|
||||
// Arguments:
|
||||
// - <unused>
|
||||
void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
|
||||
{
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_profile)
|
||||
{
|
||||
// We don't want to do anything if nothing is set, so check for that first
|
||||
if (static_cast<int>(_profile.BellStyle()) != 0)
|
||||
{
|
||||
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible))
|
||||
{
|
||||
// Audible is set, play the sound
|
||||
auto sounds{ _profile.BellSound() };
|
||||
if (sounds && sounds.Size() > 0)
|
||||
{
|
||||
winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW<std::wstring>(sounds.GetAt(rand() % sounds.Size()).c_str()) };
|
||||
winrt::Windows::Foundation::Uri uri{ soundPath };
|
||||
_playBellSound(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
|
||||
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Window))
|
||||
{
|
||||
_control.BellLightOn();
|
||||
}
|
||||
|
||||
// raise the event with the bool value corresponding to the taskbar flag
|
||||
_PaneRaiseBellHandlers(nullptr, WI_IsFlagSet(_profile.BellStyle(), winrt::Microsoft::Terminal::Settings::Model::BellStyle::Taskbar));
|
||||
}
|
||||
return control.ConnectionState() >= ConnectionState::Closed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Event Description:
|
||||
@@ -1207,7 +985,7 @@ void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspect
|
||||
// - <unused>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::_ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
void Pane::_ContentGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const RoutedEventArgs& /* args */)
|
||||
{
|
||||
auto f = FocusState::Programmatic;
|
||||
@@ -1215,17 +993,17 @@ void Pane::_ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectabl
|
||||
{
|
||||
f = o.FocusState();
|
||||
}
|
||||
_GotFocusHandlers(shared_from_this(), f);
|
||||
GotFocus.raise(shared_from_this(), f);
|
||||
}
|
||||
|
||||
// Event Description:
|
||||
// - Called when our control loses focus. We'll use this to trigger our LostFocus
|
||||
// callback. The tab that's hosting us should have registered a callback which
|
||||
// can be used to update its own internal focus state
|
||||
void Pane::_ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectable& /* sender */,
|
||||
void Pane::_ContentLostFocusHandler(const winrt::Windows::Foundation::IInspectable& /* sender */,
|
||||
const RoutedEventArgs& /* args */)
|
||||
{
|
||||
_LostFocusHandlers(shared_from_this());
|
||||
LostFocus.raise(shared_from_this());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1237,7 +1015,7 @@ void Pane::_ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectab
|
||||
void Pane::Close()
|
||||
{
|
||||
// Fire our Closed event to tell our parent that we should be removed.
|
||||
_ClosedHandlers(nullptr, nullptr);
|
||||
Closed.raise(nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1245,21 +1023,9 @@ void Pane::Close()
|
||||
// and connections beneath it.
|
||||
void Pane::Shutdown()
|
||||
{
|
||||
// Clear out our media player callbacks, and stop any playing media. This
|
||||
// will prevent the callback from being triggered after we've closed, and
|
||||
// also make sure that our sound stops when we're closed.
|
||||
if (_bellPlayer)
|
||||
{
|
||||
_bellPlayer.Pause();
|
||||
_bellPlayer.Source(nullptr);
|
||||
_bellPlayer.Close();
|
||||
_bellPlayer = nullptr;
|
||||
_bellPlayerCreated = false;
|
||||
}
|
||||
|
||||
if (_IsLeaf())
|
||||
{
|
||||
_control.Close();
|
||||
_content.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1314,7 +1080,14 @@ TermControl Pane::GetLastFocusedTerminalControl()
|
||||
{
|
||||
if (p->_IsLeaf())
|
||||
{
|
||||
return p->_control;
|
||||
if (const auto& terminalPane{ p->_content.try_as<TerminalPaneContent>() })
|
||||
{
|
||||
return terminalPane.GetTerminal();
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
pane = p;
|
||||
}
|
||||
@@ -1322,7 +1095,38 @@ TermControl Pane::GetLastFocusedTerminalControl()
|
||||
}
|
||||
return _firstChild->GetLastFocusedTerminalControl();
|
||||
}
|
||||
return _control;
|
||||
|
||||
if (const auto& terminalPane{ _content.try_as<TerminalPaneContent>() })
|
||||
{
|
||||
return terminalPane.GetTerminal();
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
IPaneContent Pane::GetLastFocusedContent()
|
||||
{
|
||||
if (!_IsLeaf())
|
||||
{
|
||||
if (_lastActive)
|
||||
{
|
||||
auto pane = shared_from_this();
|
||||
while (const auto p = pane->_parentChildPath.lock())
|
||||
{
|
||||
if (p->_IsLeaf())
|
||||
{
|
||||
return p->_content;
|
||||
}
|
||||
pane = p;
|
||||
}
|
||||
// We didn't find our child somehow, they might have closed under us.
|
||||
}
|
||||
return _firstChild->GetLastFocusedContent();
|
||||
}
|
||||
|
||||
return _content;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1332,9 +1136,16 @@ TermControl Pane::GetLastFocusedTerminalControl()
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - nullptr if this Pane is a parent, otherwise the TermControl of this Pane.
|
||||
TermControl Pane::GetTerminalControl()
|
||||
TermControl Pane::GetTerminalControl() const
|
||||
{
|
||||
return _IsLeaf() ? _control : nullptr;
|
||||
if (const auto& terminalPane{ _getTerminalContent() })
|
||||
{
|
||||
return terminalPane.GetTerminal();
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1381,19 +1192,11 @@ void Pane::SetActive()
|
||||
Profile Pane::GetFocusedProfile()
|
||||
{
|
||||
auto lastFocused = GetActivePane();
|
||||
return lastFocused ? lastFocused->_profile : nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if the connection state of this pane is closed. If this Pane is not a leaf this will
|
||||
// return false.
|
||||
// Arguments:
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - true if the connection state of this Pane is closed.
|
||||
bool Pane::IsConnectionClosed() const
|
||||
{
|
||||
return _control && _control.ConnectionState() >= ConnectionState::Closed;
|
||||
if (const auto& terminalPane{ lastFocused->_getTerminalContent() })
|
||||
{
|
||||
return terminalPane.GetProfile();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1465,10 +1268,10 @@ void Pane::UpdateVisuals()
|
||||
// - <none>
|
||||
void Pane::_Focus()
|
||||
{
|
||||
_GotFocusHandlers(shared_from_this(), FocusState::Programmatic);
|
||||
if (const auto& control = GetLastFocusedTerminalControl())
|
||||
GotFocus.raise(shared_from_this(), FocusState::Programmatic);
|
||||
if (const auto& lastContent{ GetLastFocusedContent() })
|
||||
{
|
||||
control.Focus(FocusState::Programmatic);
|
||||
lastContent.Focus(FocusState::Programmatic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,20 +1311,22 @@ void Pane::_FocusFirstChild()
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Updates the settings of this pane, presuming that it is a leaf.
|
||||
// Arguments:
|
||||
// - settings: The new TerminalSettings to apply to any matching controls
|
||||
// - profile: The profile from which these settings originated.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::UpdateSettings(const TerminalSettingsCreateResult& settings, const Profile& profile)
|
||||
void Pane::UpdateSettings(const CascadiaSettings& settings, const winrt::TerminalApp::TerminalSettingsCache& cache)
|
||||
{
|
||||
assert(_IsLeaf());
|
||||
|
||||
_profile = profile;
|
||||
|
||||
_control.UpdateControlSettings(settings.DefaultSettings(), settings.UnfocusedSettings());
|
||||
if (_content)
|
||||
{
|
||||
// We need to do a bit more work here for terminal
|
||||
// panes. They need to know about the profile that was used for
|
||||
// them, and about the focused/unfocused settings.
|
||||
if (const auto& terminalPaneContent{ _content.try_as<TerminalPaneContent>() })
|
||||
{
|
||||
terminalPaneContent.UpdateTerminalSettings(cache);
|
||||
}
|
||||
else
|
||||
{
|
||||
_content.UpdateSettings(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -1573,7 +1378,7 @@ std::shared_ptr<Pane> Pane::DetachPane(std::shared_ptr<Pane> pane)
|
||||
auto detached = isFirstChild ? _firstChild : _secondChild;
|
||||
// Remove the child from the tree, replace the current node with the
|
||||
// other child.
|
||||
_CloseChild(isFirstChild, true);
|
||||
_CloseChild(isFirstChild);
|
||||
|
||||
// Update the borders on this pane and any children to match if we have
|
||||
// no parent.
|
||||
@@ -1582,7 +1387,7 @@ std::shared_ptr<Pane> Pane::DetachPane(std::shared_ptr<Pane> pane)
|
||||
|
||||
// Trigger the detached event on each child
|
||||
detached->WalkTree([](auto pane) {
|
||||
pane->_DetachedHandlers(pane);
|
||||
pane->Detached.raise(pane);
|
||||
});
|
||||
|
||||
return detached;
|
||||
@@ -1602,12 +1407,9 @@ std::shared_ptr<Pane> Pane::DetachPane(std::shared_ptr<Pane> pane)
|
||||
// Arguments:
|
||||
// - closeFirst: if true, the first child should be closed, and the second
|
||||
// should be preserved, and vice-versa for false.
|
||||
// - isDetaching: if true, then the pane event handlers for the closed child
|
||||
// should be kept, this way they don't have to be recreated when it is later
|
||||
// reattached to a tree somewhere as the control moves with the pane.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
void Pane::_CloseChild(const bool closeFirst)
|
||||
{
|
||||
// If we're a leaf, then chances are both our children closed in close
|
||||
// succession. We waited on the lock while the other child was closed, so
|
||||
@@ -1643,35 +1445,16 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
_borders = _GetCommonBorders();
|
||||
|
||||
// take the control, profile, id and isDefTermSession of the pane that _wasn't_ closed.
|
||||
_control = remainingChild->_control;
|
||||
_connectionState = remainingChild->_connectionState;
|
||||
_profile = remainingChild->_profile;
|
||||
_content = remainingChild->_content;
|
||||
_id = remainingChild->Id();
|
||||
_isDefTermSession = remainingChild->_isDefTermSession;
|
||||
|
||||
// Add our new event handler before revoking the old one.
|
||||
_setupControlEvents();
|
||||
|
||||
// Revoke the old event handlers. Remove both the handlers for the panes
|
||||
// themselves closing, and remove their handlers for their controls
|
||||
// closing. At this point, if the remaining child's control is closed,
|
||||
// they'll trigger only our event handler for the control's close.
|
||||
|
||||
// However, if we are detaching the pane we want to keep its control
|
||||
// handlers since it is just getting moved.
|
||||
if (!isDetaching)
|
||||
{
|
||||
closedChild->WalkTree([](auto p) {
|
||||
if (p->_IsLeaf())
|
||||
{
|
||||
p->_removeControlEvents();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
closedChild->Closed(closedChildClosedToken);
|
||||
remainingChild->Closed(remainingChildClosedToken);
|
||||
remainingChild->_removeControlEvents();
|
||||
|
||||
// If we or either of our children was focused, we want to take that
|
||||
// focus from them.
|
||||
@@ -1691,7 +1474,8 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
|
||||
// Reattach the TermControl to our grid.
|
||||
_root.Children().Append(_borderFirst);
|
||||
_borderFirst.Child(_control);
|
||||
const auto& control{ _content.GetRoot() };
|
||||
_borderFirst.Child(control);
|
||||
|
||||
// Make sure to set our _splitState before focusing the control. If you
|
||||
// fail to do this, when the tab handles the GotFocus event and asks us
|
||||
@@ -1700,14 +1484,17 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
_splitState = SplitState::None;
|
||||
|
||||
// re-attach our handler for the control's GotFocus event.
|
||||
_gotFocusRevoker = _control.GotFocus(winrt::auto_revoke, { this, &Pane::_ControlGotFocusHandler });
|
||||
_lostFocusRevoker = _control.LostFocus(winrt::auto_revoke, { this, &Pane::_ControlLostFocusHandler });
|
||||
if (control)
|
||||
{
|
||||
_gotFocusRevoker = control.GotFocus(winrt::auto_revoke, { this, &Pane::_ContentGotFocusHandler });
|
||||
_lostFocusRevoker = control.LostFocus(winrt::auto_revoke, { this, &Pane::_ContentLostFocusHandler });
|
||||
}
|
||||
|
||||
// If we're inheriting the "last active" state from one of our children,
|
||||
// focus our control now. This should trigger our own GotFocus event.
|
||||
if (usedToFocusClosedChildsTerminal || _lastActive)
|
||||
{
|
||||
_control.Focus(FocusState::Programmatic);
|
||||
_content.Focus(FocusState::Programmatic);
|
||||
|
||||
// See GH#7252
|
||||
// Manually fire off the GotFocus event. Typically, this is done
|
||||
@@ -1717,7 +1504,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
// the control. Because Tab is relying on GotFocus to know who the
|
||||
// active pane in the tree is, without this call, _no one_ will be
|
||||
// the active pane any longer.
|
||||
_GotFocusHandlers(shared_from_this(), FocusState::Programmatic);
|
||||
GotFocus.raise(shared_from_this(), FocusState::Programmatic);
|
||||
}
|
||||
|
||||
_UpdateBorders();
|
||||
@@ -1746,15 +1533,6 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
// Remove the event handlers on the old children
|
||||
remainingChild->Closed(remainingChildClosedToken);
|
||||
closedChild->Closed(closedChildClosedToken);
|
||||
if (!isDetaching)
|
||||
{
|
||||
closedChild->WalkTree([](auto p) {
|
||||
if (p->_IsLeaf())
|
||||
{
|
||||
p->_removeControlEvents();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Reset our UI:
|
||||
_root.Children().Clear();
|
||||
@@ -1828,7 +1606,7 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching)
|
||||
}
|
||||
|
||||
// Notify the discarded child that it was closed by its parent
|
||||
closedChild->_ClosedByParentHandlers();
|
||||
closedChild->ClosedByParent.raise();
|
||||
}
|
||||
|
||||
void Pane::_CloseChildRoutine(const bool closeFirst)
|
||||
@@ -1847,7 +1625,7 @@ void Pane::_CloseChildRoutine(const bool closeFirst)
|
||||
// this one doesn't seem to.
|
||||
if (!animationsEnabledInOS || !animationsEnabledInApp || eitherChildZoomed)
|
||||
{
|
||||
_CloseChild(closeFirst, false);
|
||||
_CloseChild(closeFirst);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1950,7 +1728,7 @@ void Pane::_CloseChildRoutine(const bool closeFirst)
|
||||
{
|
||||
// We don't need to manually undo any of the above trickiness.
|
||||
// We're going to re-parent the child's content into us anyways
|
||||
pane->_CloseChild(closeFirst, false);
|
||||
pane->_CloseChild(closeFirst);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -2173,7 +1951,7 @@ void Pane::_SetupEntranceAnimation()
|
||||
auto child = isFirstChild ? _firstChild : _secondChild;
|
||||
auto childGrid = child->_root;
|
||||
// If we are splitting a parent pane this may be null
|
||||
auto control = child->_control;
|
||||
auto control = child->_content ? child->_content.GetRoot() : nullptr;
|
||||
// Build up our animation:
|
||||
// * it'll take as long as our duration (200ms)
|
||||
// * it'll change the value of our property from 0 to secondSize
|
||||
@@ -2494,9 +2272,6 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
|
||||
|
||||
if (_IsLeaf())
|
||||
{
|
||||
// revoke our handler - the child will take care of the control now.
|
||||
_removeControlEvents();
|
||||
|
||||
// Remove our old GotFocus handler from the control. We don't want the
|
||||
// control telling us that it's now focused, we want it telling its new
|
||||
// parent.
|
||||
@@ -2525,11 +2300,8 @@ std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> Pane::_Split(SplitDirect
|
||||
else
|
||||
{
|
||||
// Move our control, guid, isDefTermSession into the first one.
|
||||
_firstChild = std::make_shared<Pane>(_profile, _control);
|
||||
_firstChild->_connectionState = std::exchange(_connectionState, ConnectionState::NotConnected);
|
||||
_profile = nullptr;
|
||||
_control = { nullptr };
|
||||
_firstChild->_isDefTermSession = _isDefTermSession;
|
||||
_firstChild = std::make_shared<Pane>(_content);
|
||||
_content = nullptr;
|
||||
_firstChild->_broadcastEnabled = _broadcastEnabled;
|
||||
}
|
||||
|
||||
@@ -2852,8 +2624,16 @@ float Pane::CalcSnappedDimension(const bool widthOrHeight, const float dimension
|
||||
// If requested size is already snapped, then both returned values equal this value.
|
||||
Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const float dimension) const
|
||||
{
|
||||
const auto direction{ widthOrHeight ? PaneSnapDirection::Width : PaneSnapDirection::Height };
|
||||
|
||||
if (_IsLeaf())
|
||||
{
|
||||
const auto& snappable{ _content.try_as<ISnappable>() };
|
||||
if (!snappable)
|
||||
{
|
||||
return { dimension, dimension };
|
||||
}
|
||||
|
||||
// If we're a leaf pane, align to the grid of controlling terminal
|
||||
|
||||
const auto minSize = _GetMinSize();
|
||||
@@ -2864,8 +2644,10 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
|
||||
return { minDimension, minDimension };
|
||||
}
|
||||
|
||||
auto lower = _control.SnapDimensionToGrid(widthOrHeight, dimension);
|
||||
if (widthOrHeight)
|
||||
auto lower = snappable.SnapDownToGrid(widthOrHeight ? PaneSnapDirection::Width : PaneSnapDirection::Height,
|
||||
dimension);
|
||||
|
||||
if (direction == PaneSnapDirection::Width)
|
||||
{
|
||||
lower += WI_IsFlagSet(_borders, Borders::Left) ? PaneBorderSize : 0;
|
||||
lower += WI_IsFlagSet(_borders, Borders::Right) ? PaneBorderSize : 0;
|
||||
@@ -2884,8 +2666,10 @@ Pane::SnapSizeResult Pane::_CalcSnappedDimension(const bool widthOrHeight, const
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto cellSize = _control.CharacterDimensions();
|
||||
const auto higher = lower + (widthOrHeight ? cellSize.Width : cellSize.Height);
|
||||
const auto cellSize = snappable.GridSize();
|
||||
const auto higher = lower + (direction == PaneSnapDirection::Width ?
|
||||
cellSize.Width :
|
||||
cellSize.Height);
|
||||
return { lower, higher };
|
||||
}
|
||||
}
|
||||
@@ -2931,21 +2715,36 @@ void Pane::_AdvanceSnappedDimension(const bool widthOrHeight, LayoutSizeNode& si
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
|
||||
// is true, see below).
|
||||
|
||||
if (sizeNode.isMinimumSize)
|
||||
const auto& snappable{ _content.try_as<ISnappable>() };
|
||||
if (snappable)
|
||||
{
|
||||
// If the node is of its minimum size, this size might not be snapped (it might
|
||||
// be, say, half a character, or fixed 10 pixels), so snap it upward. It might
|
||||
// however be already snapped, so add 1 to make sure it really increases
|
||||
// (not strictly necessary but to avoid surprises).
|
||||
sizeNode.size = _CalcSnappedDimension(widthOrHeight, sizeNode.size + 1).higher;
|
||||
// We're a leaf pane, so just add one more row or column (unless isMinimumSize
|
||||
// is true, see below).
|
||||
|
||||
if (sizeNode.isMinimumSize)
|
||||
{
|
||||
// If the node is of its minimum size, this size might not be snapped (it might
|
||||
// be, say, half a character, or fixed 10 pixels), so snap it upward. It might
|
||||
// however be already snapped, so add 1 to make sure it really increases
|
||||
// (not strictly necessary but to avoid surprises).
|
||||
sizeNode.size = _CalcSnappedDimension(widthOrHeight,
|
||||
sizeNode.size + 1)
|
||||
.higher;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto cellSize = snappable.GridSize();
|
||||
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto cellSize = _control.CharacterDimensions();
|
||||
sizeNode.size += widthOrHeight ? cellSize.Width : cellSize.Height;
|
||||
// If we're a leaf that didn't have a TermControl, then just increment
|
||||
// by one. We have to increment by _some_ value, because this is used in
|
||||
// a while() loop to find the next bigger size we can snap to. But since
|
||||
// a non-terminal control doesn't really care what size it's snapped to,
|
||||
// we can just say "one pixel larger is the next snap point"
|
||||
sizeNode.size += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -3050,7 +2849,7 @@ Size Pane::_GetMinSize() const
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
auto controlSize = _control.MinimumSize();
|
||||
auto controlSize = _content.MinSize();
|
||||
auto newWidth = controlSize.Width;
|
||||
auto newHeight = controlSize.Height;
|
||||
|
||||
@@ -3148,14 +2947,17 @@ int Pane::GetLeafPaneCount() const noexcept
|
||||
// created via default handoff
|
||||
void Pane::FinalizeConfigurationGivenDefault()
|
||||
{
|
||||
_isDefTermSession = true;
|
||||
if (const auto& terminalPane{ _content.try_as<TerminalPaneContent>() })
|
||||
{
|
||||
terminalPane.MarkAsDefterm();
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns true if the pane or one of its descendants is read-only
|
||||
bool Pane::ContainsReadOnly() const
|
||||
{
|
||||
return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
|
||||
return _IsLeaf() ? _content.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -3170,8 +2972,8 @@ void Pane::CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& s
|
||||
{
|
||||
if (_IsLeaf())
|
||||
{
|
||||
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_control.TaskbarState(),
|
||||
_control.TaskbarProgress()) };
|
||||
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_content.TaskbarState(),
|
||||
_content.TaskbarProgress()) };
|
||||
states.push_back(tbState);
|
||||
}
|
||||
else
|
||||
@@ -3186,9 +2988,12 @@ void Pane::EnableBroadcast(bool enabled)
|
||||
if (_IsLeaf())
|
||||
{
|
||||
_broadcastEnabled = enabled;
|
||||
_control.CursorVisibility(enabled ?
|
||||
CursorDisplayState::Shown :
|
||||
CursorDisplayState::Default);
|
||||
if (const auto& termControl{ GetTerminalControl() })
|
||||
{
|
||||
termControl.CursorVisibility(enabled ?
|
||||
CursorDisplayState::Shown :
|
||||
CursorDisplayState::Default);
|
||||
}
|
||||
UpdateVisuals();
|
||||
}
|
||||
else
|
||||
@@ -3205,9 +3010,12 @@ void Pane::BroadcastKey(const winrt::Microsoft::Terminal::Control::TermControl&
|
||||
const bool keyDown)
|
||||
{
|
||||
WalkTree([&](const auto& pane) {
|
||||
if (pane->_IsLeaf() && pane->_control != sourceControl && !pane->_control.ReadOnly())
|
||||
if (const auto& termControl{ pane->GetTerminalControl() })
|
||||
{
|
||||
pane->_control.RawWriteKeyEvent(vkey, scanCode, modifiers, keyDown);
|
||||
if (termControl != sourceControl && !termControl.ReadOnly())
|
||||
{
|
||||
termControl.RawWriteKeyEvent(vkey, scanCode, modifiers, keyDown);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3218,9 +3026,12 @@ void Pane::BroadcastChar(const winrt::Microsoft::Terminal::Control::TermControl&
|
||||
const winrt::Microsoft::Terminal::Core::ControlKeyStates modifiers)
|
||||
{
|
||||
WalkTree([&](const auto& pane) {
|
||||
if (pane->_IsLeaf() && pane->_control != sourceControl && !pane->_control.ReadOnly())
|
||||
if (const auto& termControl{ pane->GetTerminalControl() })
|
||||
{
|
||||
pane->_control.RawWriteChar(character, scanCode, modifiers);
|
||||
if (termControl != sourceControl && !termControl.ReadOnly())
|
||||
{
|
||||
termControl.RawWriteChar(character, scanCode, modifiers);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3229,19 +3040,16 @@ void Pane::BroadcastString(const winrt::Microsoft::Terminal::Control::TermContro
|
||||
const winrt::hstring& text)
|
||||
{
|
||||
WalkTree([&](const auto& pane) {
|
||||
if (pane->_IsLeaf() && pane->_control != sourceControl && !pane->_control.ReadOnly())
|
||||
if (const auto& termControl{ pane->GetTerminalControl() })
|
||||
{
|
||||
pane->_control.RawWriteString(text);
|
||||
if (termControl != sourceControl && !termControl.ReadOnly())
|
||||
{
|
||||
termControl.RawWriteString(text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Pane::_ControlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*e*/)
|
||||
{
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::_ComputeBorderColor()
|
||||
{
|
||||
if (_lastActive)
|
||||
@@ -3249,7 +3057,7 @@ winrt::Windows::UI::Xaml::Media::SolidColorBrush Pane::_ComputeBorderColor()
|
||||
return _themeResources.focusedBorderBrush;
|
||||
}
|
||||
|
||||
if (_broadcastEnabled && (_IsLeaf() && !_control.ReadOnly()))
|
||||
if (_broadcastEnabled && (_IsLeaf() && !_content.ReadOnly()))
|
||||
{
|
||||
return _themeResources.broadcastBorderBrush;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "TaskbarState.h"
|
||||
#include "TerminalPaneContent.h"
|
||||
|
||||
// fwdecl unittest classes
|
||||
namespace TerminalAppLocalTests
|
||||
@@ -61,8 +62,7 @@ struct PaneResources
|
||||
class Pane : public std::enable_shared_from_this<Pane>
|
||||
{
|
||||
public:
|
||||
Pane(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
|
||||
const winrt::Microsoft::Terminal::Control::TermControl& control,
|
||||
Pane(const winrt::TerminalApp::IPaneContent& content,
|
||||
const bool lastFocused = false);
|
||||
|
||||
Pane(std::shared_ptr<Pane> first,
|
||||
@@ -73,7 +73,8 @@ public:
|
||||
|
||||
std::shared_ptr<Pane> GetActivePane();
|
||||
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
|
||||
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
|
||||
winrt::TerminalApp::IPaneContent GetLastFocusedContent();
|
||||
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl() const;
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
|
||||
bool IsConnectionClosed() const;
|
||||
|
||||
@@ -82,10 +83,15 @@ public:
|
||||
// - If this is a branch/root pane, return nullptr.
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile GetProfile() const
|
||||
{
|
||||
return _profile;
|
||||
if (const auto& c{ _content.try_as<winrt::TerminalApp::TerminalPaneContent>() })
|
||||
{
|
||||
return c.GetProfile();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Controls::Grid GetRootElement();
|
||||
winrt::TerminalApp::IPaneContent GetContent() const noexcept { return _IsLeaf() ? _content : nullptr; }
|
||||
|
||||
bool WasLastFocused() const noexcept;
|
||||
void UpdateVisuals();
|
||||
@@ -102,8 +108,7 @@ public:
|
||||
BuildStartupState BuildStartupActions(uint32_t currentId, uint32_t nextId, const bool asContent = false, const bool asMovePane = false);
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetTerminalArgsForPane(const bool asContent = false) const;
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::Profile& profile);
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings, const winrt::TerminalApp::TerminalSettingsCache& cache);
|
||||
bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
|
||||
std::shared_ptr<Pane> NavigateDirection(const std::shared_ptr<Pane> sourcePane,
|
||||
const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction,
|
||||
@@ -210,16 +215,15 @@ public:
|
||||
|
||||
void CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states);
|
||||
|
||||
WINRT_CALLBACK(ClosedByParent, winrt::delegate<>);
|
||||
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
|
||||
til::event<winrt::delegate<>> ClosedByParent;
|
||||
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> Closed;
|
||||
|
||||
using gotFocusArgs = winrt::delegate<std::shared_ptr<Pane>, winrt::Windows::UI::Xaml::FocusState>;
|
||||
|
||||
WINRT_CALLBACK(GotFocus, gotFocusArgs);
|
||||
WINRT_CALLBACK(LostFocus, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
WINRT_CALLBACK(PaneRaiseBell, winrt::Windows::Foundation::EventHandler<bool>);
|
||||
WINRT_CALLBACK(Detached, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
WINRT_CALLBACK(RestartTerminalRequested, winrt::delegate<std::shared_ptr<Pane>>);
|
||||
til::event<gotFocusArgs> GotFocus;
|
||||
til::event<winrt::delegate<std::shared_ptr<Pane>>> LostFocus;
|
||||
til::event<winrt::Windows::Foundation::EventHandler<bool>> PaneRaiseBell;
|
||||
til::event<winrt::delegate<std::shared_ptr<Pane>>> Detached;
|
||||
|
||||
private:
|
||||
struct PanePoint;
|
||||
@@ -239,10 +243,8 @@ private:
|
||||
std::shared_ptr<Pane> _secondChild{ nullptr };
|
||||
SplitState _splitState{ SplitState::None };
|
||||
float _desiredSplitPosition;
|
||||
winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr };
|
||||
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
|
||||
bool _isDefTermSession{ false };
|
||||
|
||||
winrt::TerminalApp::IPaneContent _content{ nullptr };
|
||||
#pragma endregion
|
||||
|
||||
std::optional<uint32_t> _id;
|
||||
@@ -252,17 +254,6 @@ private:
|
||||
winrt::event_token _firstClosedToken{ 0 };
|
||||
winrt::event_token _secondClosedToken{ 0 };
|
||||
|
||||
struct ControlEventTokens
|
||||
{
|
||||
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::WarningBell_revoker _WarningBell;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::CloseTerminalRequested_revoker _CloseTerminalRequested;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::RestartTerminalRequested_revoker _RestartTerminalRequested;
|
||||
winrt::Microsoft::Terminal::Control::TermControl::ReadOnlyChanged_revoker _ReadOnlyChanged;
|
||||
} _controlEvents;
|
||||
void _setupControlEvents();
|
||||
void _removeControlEvents();
|
||||
|
||||
winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker;
|
||||
winrt::Windows::UI::Xaml::UIElement::LostFocus_revoker _lostFocusRevoker;
|
||||
|
||||
@@ -271,13 +262,14 @@ private:
|
||||
bool _zoomed{ false };
|
||||
bool _broadcastEnabled{ false };
|
||||
|
||||
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
|
||||
bool _bellPlayerCreated{ false };
|
||||
|
||||
bool _IsLeaf() const noexcept;
|
||||
bool _HasFocusedChild() const noexcept;
|
||||
void _SetupChildCloseHandlers();
|
||||
bool _HasChild(const std::shared_ptr<Pane> child);
|
||||
winrt::TerminalApp::TerminalPaneContent _getTerminalContent() const
|
||||
{
|
||||
return _IsLeaf() ? _content.try_as<winrt::TerminalApp::TerminalPaneContent>() : nullptr;
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
|
||||
const float splitSize,
|
||||
@@ -303,24 +295,16 @@ private:
|
||||
const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction,
|
||||
const PanePoint offset);
|
||||
|
||||
void _CloseChild(const bool closeFirst, const bool isDetaching);
|
||||
void _CloseChild(const bool closeFirst);
|
||||
void _CloseChildRoutine(const bool closeFirst);
|
||||
|
||||
void _Focus();
|
||||
void _FocusFirstChild();
|
||||
winrt::fire_and_forget _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
void _ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& e);
|
||||
void _ControlGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
void _ContentGotFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void _ControlLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
void _ContentLostFocusHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
|
||||
void _ControlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e);
|
||||
|
||||
void _CloseTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
void _RestartTerminalRequestedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
|
||||
|
||||
std::pair<float, float> _CalcChildrenSizes(const float fullSize) const;
|
||||
SnapChildrenSizeResult _CalcSnappedChildrenSizes(const bool widthOrHeight, const float fullSize) const;
|
||||
SnapSizeResult _CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
|
||||
@@ -331,8 +315,6 @@ private:
|
||||
|
||||
SplitState _convertAutomaticOrDirectionalSplitState(const winrt::Microsoft::Terminal::Settings::Model::SplitDirection& splitType) const;
|
||||
|
||||
winrt::fire_and_forget _playBellSound(winrt::Windows::Foundation::Uri uri);
|
||||
|
||||
// Function Description:
|
||||
// - Returns true if the given direction can be used with the given split
|
||||
// type.
|
||||
|
||||
6
src/cascadia/TerminalApp/PaneArgs.cpp
Normal file
6
src/cascadia/TerminalApp/PaneArgs.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "PaneArgs.h"
|
||||
#include "BellEventArgs.g.cpp"
|
||||
18
src/cascadia/TerminalApp/PaneArgs.h
Normal file
18
src/cascadia/TerminalApp/PaneArgs.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BellEventArgs.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct BellEventArgs : public BellEventArgsT<BellEventArgs>
|
||||
{
|
||||
public:
|
||||
BellEventArgs(bool flashTaskbar) :
|
||||
FlashTaskbar(flashTaskbar) {}
|
||||
|
||||
til::property<bool> FlashTaskbar;
|
||||
};
|
||||
};
|
||||
68
src/cascadia/TerminalApp/ScratchpadContent.cpp
Normal file
68
src/cascadia/TerminalApp/ScratchpadContent.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "ScratchpadContent.h"
|
||||
#include "PaneArgs.h"
|
||||
#include "ScratchpadContent.g.cpp"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
ScratchpadContent::ScratchpadContent()
|
||||
{
|
||||
_root = winrt::Windows::UI::Xaml::Controls::Grid{};
|
||||
// Vertical and HorizontalAlignment are Stretch by default
|
||||
|
||||
auto res = Windows::UI::Xaml::Application::Current().Resources();
|
||||
auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush"));
|
||||
_root.Background(bg.try_as<Media::Brush>());
|
||||
|
||||
_box = winrt::Windows::UI::Xaml::Controls::TextBox{};
|
||||
_box.Margin({ 10, 10, 10, 10 });
|
||||
_box.AcceptsReturn(true);
|
||||
_box.TextWrapping(TextWrapping::Wrap);
|
||||
_root.Children().Append(_box);
|
||||
}
|
||||
|
||||
void ScratchpadContent::UpdateSettings(const CascadiaSettings& /*settings*/)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::FrameworkElement ScratchpadContent::GetRoot()
|
||||
{
|
||||
return _root;
|
||||
}
|
||||
winrt::Windows::Foundation::Size ScratchpadContent::MinSize()
|
||||
{
|
||||
return { 1, 1 };
|
||||
}
|
||||
void ScratchpadContent::Focus(winrt::Windows::UI::Xaml::FocusState reason)
|
||||
{
|
||||
_box.Focus(reason);
|
||||
}
|
||||
void ScratchpadContent::Close()
|
||||
{
|
||||
CloseRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
NewTerminalArgs ScratchpadContent::GetNewTerminalArgs(const bool /* asContent */) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::hstring ScratchpadContent::Icon() const
|
||||
{
|
||||
static constexpr std::wstring_view glyph{ L"\xe70b" }; // QuickNote
|
||||
return winrt::hstring{ glyph };
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::Brush ScratchpadContent::BackgroundBrush()
|
||||
{
|
||||
return _root.Background();
|
||||
}
|
||||
}
|
||||
43
src/cascadia/TerminalApp/ScratchpadContent.h
Normal file
43
src/cascadia/TerminalApp/ScratchpadContent.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
#include "ScratchpadContent.g.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct ScratchpadContent : ScratchpadContentT<ScratchpadContent>
|
||||
{
|
||||
ScratchpadContent();
|
||||
|
||||
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
|
||||
|
||||
winrt::Windows::Foundation::Size MinSize();
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
|
||||
void Close();
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const;
|
||||
|
||||
winrt::hstring Title() { return L"Scratchpad"; }
|
||||
uint64_t TaskbarState() { return 0; }
|
||||
uint64_t TaskbarProgress() { return 0; }
|
||||
bool ReadOnly() { return false; }
|
||||
winrt::hstring Icon() const;
|
||||
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept { return nullptr; }
|
||||
winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush();
|
||||
|
||||
til::typed_event<> CloseRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::BellEventArgs> BellRequested;
|
||||
til::typed_event<> TitleChanged;
|
||||
til::typed_event<> TabColorChanged;
|
||||
til::typed_event<> TaskbarProgressChanged;
|
||||
til::typed_event<> ConnectionStateChanged;
|
||||
til::typed_event<> ReadOnlyChanged;
|
||||
til::typed_event<> FocusRequested;
|
||||
|
||||
private:
|
||||
winrt::Windows::UI::Xaml::Controls::Grid _root{ nullptr };
|
||||
winrt::Windows::UI::Xaml::Controls::TextBox _box{ nullptr };
|
||||
};
|
||||
}
|
||||
86
src/cascadia/TerminalApp/SettingsPaneContent.cpp
Normal file
86
src/cascadia/TerminalApp/SettingsPaneContent.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "SettingsPaneContent.h"
|
||||
#include "PaneArgs.h"
|
||||
#include "SettingsPaneContent.g.cpp"
|
||||
#include "Utils.h"
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
#define ASSERT_UI_THREAD() assert(_sui.Dispatcher().HasThreadAccess())
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
SettingsPaneContent::SettingsPaneContent(CascadiaSettings settings)
|
||||
{
|
||||
_sui = winrt::Microsoft::Terminal::Settings::Editor::MainPage{ settings };
|
||||
|
||||
// Stash away the current requested theme of the app. We'll need that in
|
||||
// _BackgroundBrush() to do a theme-aware resource lookup
|
||||
_requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme();
|
||||
}
|
||||
|
||||
void SettingsPaneContent::UpdateSettings(const CascadiaSettings& settings)
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
_sui.UpdateSettings(settings);
|
||||
|
||||
_requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme();
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::FrameworkElement SettingsPaneContent::GetRoot()
|
||||
{
|
||||
return _sui;
|
||||
}
|
||||
winrt::Windows::Foundation::Size SettingsPaneContent::MinSize()
|
||||
{
|
||||
return { 1, 1 };
|
||||
}
|
||||
void SettingsPaneContent::Focus(winrt::Windows::UI::Xaml::FocusState reason)
|
||||
{
|
||||
if (reason != FocusState::Unfocused)
|
||||
{
|
||||
_sui.as<Controls::Page>().Focus(reason);
|
||||
}
|
||||
}
|
||||
void SettingsPaneContent::Close()
|
||||
{
|
||||
CloseRequested.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
NewTerminalArgs SettingsPaneContent::GetNewTerminalArgs(const bool /* asContent */) const
|
||||
{
|
||||
// For now, we're doing a terrible thing in TerminalTab itself to
|
||||
// generate an OpenSettings action manually, without asking for the pane
|
||||
// structure.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::hstring SettingsPaneContent::Icon() const
|
||||
{
|
||||
// This is the Setting icon (looks like a gear)
|
||||
static constexpr std::wstring_view glyph{ L"\xE713" };
|
||||
return winrt::hstring{ glyph };
|
||||
}
|
||||
|
||||
Windows::Foundation::IReference<winrt::Windows::UI::Color> SettingsPaneContent::TabColor() const noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::Brush SettingsPaneContent::BackgroundBrush()
|
||||
{
|
||||
// Look up the color we should use for the settings tab item from our
|
||||
// resources. This should only be used for when "terminalBackground" is
|
||||
// requested.
|
||||
static const auto key = winrt::box_value(L"SettingsUiTabBrush");
|
||||
// You can't just do a Application::Current().Resources().TryLookup
|
||||
// lookup, cause the app theme never changes! Do the hacky version
|
||||
// instead.
|
||||
return ThemeLookup(Application::Current().Resources(), _requestedTheme, key).try_as<winrt::Windows::UI::Xaml::Media::Brush>();
|
||||
}
|
||||
}
|
||||
50
src/cascadia/TerminalApp/SettingsPaneContent.h
Normal file
50
src/cascadia/TerminalApp/SettingsPaneContent.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
#include "SettingsPaneContent.g.h"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct SettingsPaneContent : SettingsPaneContentT<SettingsPaneContent>
|
||||
{
|
||||
SettingsPaneContent(winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
|
||||
|
||||
void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
|
||||
|
||||
winrt::Windows::UI::Xaml::FrameworkElement GetRoot();
|
||||
winrt::Microsoft::Terminal::Settings::Editor::MainPage SettingsUI() { return _sui; }
|
||||
|
||||
winrt::Windows::Foundation::Size MinSize();
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
|
||||
void Close();
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs GetNewTerminalArgs(const bool asContent) const;
|
||||
|
||||
winrt::hstring Title() { return RS_(L"SettingsTab"); }
|
||||
uint64_t TaskbarState() { return 0; }
|
||||
uint64_t TaskbarProgress() { return 0; }
|
||||
bool ReadOnly() { return false; }
|
||||
winrt::hstring Icon() const;
|
||||
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept;
|
||||
winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush();
|
||||
|
||||
til::typed_event<> CloseRequested;
|
||||
til::typed_event<winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::BellEventArgs> BellRequested;
|
||||
til::typed_event<> TitleChanged;
|
||||
til::typed_event<> TabColorChanged;
|
||||
til::typed_event<> TaskbarProgressChanged;
|
||||
til::typed_event<> ConnectionStateChanged;
|
||||
til::typed_event<> ReadOnlyChanged;
|
||||
til::typed_event<> FocusRequested;
|
||||
|
||||
private:
|
||||
winrt::Microsoft::Terminal::Settings::Editor::MainPage _sui{ nullptr };
|
||||
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(SettingsPaneContent);
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
// 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::Control;
|
||||
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;
|
||||
}
|
||||
|
||||
#define ASSERT_UI_THREAD() assert(TabViewItem().Dispatcher().HasThreadAccess())
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
SettingsTab::SettingsTab(MainPage settingsUI,
|
||||
winrt::Windows::UI::Xaml::ElementTheme requestedTheme)
|
||||
{
|
||||
Content(settingsUI);
|
||||
_requestedTheme = requestedTheme;
|
||||
|
||||
_MakeTabViewItem();
|
||||
_CreateContextMenu();
|
||||
_CreateIcon();
|
||||
}
|
||||
|
||||
void SettingsTab::UpdateSettings(CascadiaSettings settings)
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
auto settingsUI{ Content().as<MainPage>() };
|
||||
settingsUI.UpdateSettings(settings);
|
||||
|
||||
// Stash away the current requested theme of the app. We'll need that in
|
||||
// _BackgroundBrush() to do a theme-aware resource lookup
|
||||
_requestedTheme = settings.GlobalSettings().CurrentTheme().RequestedTheme();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates a list of actions that can be run to recreate the state of this tab
|
||||
// Arguments:
|
||||
// - asContent: unused. There's nothing different we need to do when
|
||||
// serializing the settings tab for moving to another window. If we ever
|
||||
// really want to support opening the SUI to a specific page, we can
|
||||
// re-evaluate including that arg in this action then.
|
||||
// Return Value:
|
||||
// - The list of actions.
|
||||
std::vector<ActionAndArgs> SettingsTab::BuildStartupActions(const bool /*asContent*/) const
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
ActionAndArgs action;
|
||||
action.Action(ShortcutAction::OpenSettings);
|
||||
OpenSettingsArgs args{ SettingsTarget::SettingsUI };
|
||||
action.Args(args);
|
||||
|
||||
return std::vector{ std::move(action) };
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
ASSERT_UI_THREAD();
|
||||
|
||||
_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()
|
||||
{
|
||||
TabBase::_MakeTabViewItem();
|
||||
|
||||
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>
|
||||
void SettingsTab::_CreateIcon()
|
||||
{
|
||||
// This is the Setting icon (looks like a gear)
|
||||
static constexpr std::wstring_view glyph{ L"\xE713" };
|
||||
|
||||
// The TabViewItem Icon needs MUX while the IconSourceElement in the CommandPalette needs WUX...
|
||||
Icon(winrt::hstring{ glyph });
|
||||
TabViewItem().IconSource(IconPathConverter::IconSourceMUX(glyph, false));
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::Brush SettingsTab::_BackgroundBrush()
|
||||
{
|
||||
// Look up the color we should use for the settings tab item from our
|
||||
// resources. This should only be used for when "terminalBackground" is
|
||||
// requested.
|
||||
static const auto key = winrt::box_value(L"SettingsUiTabBrush");
|
||||
// You can't just do a Application::Current().Resources().TryLookup
|
||||
// lookup, cause the app theme never changes! Do the hacky version
|
||||
// instead.
|
||||
return ThemeLookup(Application::Current().Resources(), _requestedTheme, key).try_as<winrt::Windows::UI::Xaml::Media::Brush>();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*++
|
||||
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"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct SettingsTab : SettingsTabT<SettingsTab, TabBase>
|
||||
{
|
||||
public:
|
||||
SettingsTab(winrt::Microsoft::Terminal::Settings::Editor::MainPage settingsUI,
|
||||
winrt::Windows::UI::Xaml::ElementTheme requestedTheme);
|
||||
|
||||
void UpdateSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings);
|
||||
void Focus(winrt::Windows::UI::Xaml::FocusState focusState) override;
|
||||
|
||||
std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs> BuildStartupActions(const bool asContent = false) const override;
|
||||
|
||||
private:
|
||||
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
|
||||
|
||||
void _MakeTabViewItem() override;
|
||||
void _CreateIcon();
|
||||
|
||||
virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;
|
||||
};
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -268,7 +268,7 @@ namespace winrt::TerminalApp::implementation
|
||||
const auto selectedCommand = _filteredActionsView().SelectedItem();
|
||||
const auto filteredCommand{ selectedCommand.try_as<winrt::TerminalApp::FilteredCommand>() };
|
||||
|
||||
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"SelectedItem" });
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"SelectedItem" });
|
||||
|
||||
// Make sure to not send the preview if we're collapsed. This can
|
||||
// sometimes fire after we've been closed, which can trigger us to
|
||||
|
||||
@@ -50,12 +50,12 @@ namespace winrt::TerminalApp::implementation
|
||||
til::typed_event<winrt::TerminalApp::SuggestionsControl, Microsoft::Terminal::Settings::Model::Command> DispatchCommandRequested;
|
||||
til::typed_event<Windows::Foundation::IInspectable, Microsoft::Terminal::Settings::Model::Command> PreviewAction;
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, _PropertyChangedHandlers);
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, NoMatchesText, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, SearchBoxPlaceholderText, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ControlName, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParentCommandName, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, ParsedCommandLineText, PropertyChanged.raise);
|
||||
|
||||
private:
|
||||
struct winrt_object_hash
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "TabBase.idl";
|
||||
import "IDirectKeyListener.idl";
|
||||
import "HighlightedTextControl.idl";
|
||||
import "FilteredCommand.idl";
|
||||
|
||||
@@ -21,7 +20,7 @@ namespace TerminalApp
|
||||
BottomUp
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SuggestionsControl : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged, IDirectKeyListener
|
||||
[default_interface] runtimeclass SuggestionsControl : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged, Microsoft.Terminal.UI.IDirectKeyListener
|
||||
{
|
||||
SuggestionsControl();
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
AllowFocusOnInteraction="True"
|
||||
AutomationProperties.Name="{x:Bind ControlName, Mode=OneWay}"
|
||||
@@ -23,9 +24,6 @@
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParentCommandVisibilityConverter" />
|
||||
<model:IconPathConverter x:Key="IconSourceConverter" />
|
||||
|
||||
<DataTemplate x:Key="ListItemTemplate"
|
||||
x:DataType="local:FilteredCommand">
|
||||
<ListViewItem Height="32"
|
||||
@@ -161,7 +159,7 @@
|
||||
<StackPanel Grid.Row="1"
|
||||
Margin="8,0,8,8"
|
||||
Orientation="Horizontal"
|
||||
Visibility="{x:Bind ParentCommandName, Mode=OneWay, Converter={StaticResource ParentCommandVisibilityConverter}}">
|
||||
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(ParentCommandName), Mode=OneWay}">
|
||||
|
||||
<Button x:Name="_parentCommandBackButton"
|
||||
x:Uid="ParentCommandBackButton"
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace winrt::TerminalApp::implementation
|
||||
contextMenuFlyout.Closed([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_RequestFocusActiveControlHandlers();
|
||||
tab->RequestFocusActiveControl.raise();
|
||||
}
|
||||
});
|
||||
_AppendCloseMenuItems(contextMenuFlyout);
|
||||
@@ -106,7 +106,7 @@ namespace winrt::TerminalApp::implementation
|
||||
closeTabMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_CloseRequestedHandlers(nullptr, nullptr);
|
||||
tab->CloseRequested.raise(nullptr, nullptr);
|
||||
}
|
||||
});
|
||||
closeTabMenuItem.Text(RS_(L"TabClose"));
|
||||
@@ -260,7 +260,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TabViewItem().Tapped([weakThis{ get_weak() }](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
{
|
||||
tab->_RequestFocusActiveControlHandlers();
|
||||
tab->RequestFocusActiveControl.raise();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -32,23 +32,23 @@ namespace winrt::TerminalApp::implementation
|
||||
Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility CloseButtonVisibility();
|
||||
void CloseButtonVisibility(Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility visible);
|
||||
|
||||
WINRT_CALLBACK(RequestFocusActiveControl, winrt::delegate<void()>);
|
||||
til::event<winrt::delegate<void()>> RequestFocusActiveControl;
|
||||
|
||||
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
|
||||
WINRT_CALLBACK(CloseRequested, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> Closed;
|
||||
til::event<winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> CloseRequested;
|
||||
til::property_changed_event PropertyChanged;
|
||||
|
||||
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
|
||||
WINRT_PROPERTY(uint32_t, TabViewIndex, 0);
|
||||
// The TabViewNumTabs is the number of Tab objects in TerminalPage's _tabs vector.
|
||||
WINRT_PROPERTY(uint32_t, TabViewNumTabs, 0);
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, ReadOnly, _PropertyChangedHandlers, false);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Icon, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(bool, ReadOnly, PropertyChanged.raise, false);
|
||||
WINRT_PROPERTY(winrt::Microsoft::UI::Xaml::Controls::TabViewItem, TabViewItem, nullptr);
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, _PropertyChangedHandlers, nullptr);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::Windows::UI::Xaml::FrameworkElement, Content, PropertyChanged.raise, nullptr);
|
||||
|
||||
protected:
|
||||
winrt::Windows::UI::Xaml::FocusState _focusState{ winrt::Windows::UI::Xaml::FocusState::Unfocused };
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace winrt::TerminalApp::implementation
|
||||
_CloseRenameBox();
|
||||
if (!_renameCancelled)
|
||||
{
|
||||
_TitleChangeRequestedHandlers(HeaderRenamerTextBox().Text());
|
||||
TitleChangeRequested.raise(HeaderRenamerTextBox().Text());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
HeaderRenamerTextBox().Visibility(Windows::UI::Xaml::Visibility::Collapsed);
|
||||
HeaderTextBlock().Visibility(Windows::UI::Xaml::Visibility::Visible);
|
||||
_RenameEndedHandlers(*this, nullptr);
|
||||
RenameEnded.raise(*this, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,13 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
bool InRename();
|
||||
|
||||
WINRT_CALLBACK(TitleChangeRequested, TerminalApp::TitleChangeRequestedArgs);
|
||||
til::event<TerminalApp::TitleChangeRequestedArgs> TitleChangeRequested;
|
||||
til::typed_event<> RenameEnded;
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(double, RenamerMaxWidth, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, _PropertyChangedHandlers);
|
||||
|
||||
TYPED_EVENT(RenameEnded, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
til::property_changed_event PropertyChanged;
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::hstring, Title, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(double, RenamerMaxWidth, PropertyChanged.raise);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, PropertyChanged.raise);
|
||||
|
||||
private:
|
||||
bool _receivedKeyDown{ false };
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "TabRowControl.h"
|
||||
#include "ColorHelper.h"
|
||||
#include "DebugTapConnection.h"
|
||||
#include "SettingsTab.h"
|
||||
#include "..\TerminalSettingsModel\FileUtils.h"
|
||||
|
||||
#include <shlobj.h>
|
||||
@@ -63,7 +62,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - existingConnection: An optional connection that is already established to a PTY
|
||||
// for this tab to host instead of creating one.
|
||||
// If not defined, the tab will create the connection.
|
||||
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
|
||||
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs)
|
||||
try
|
||||
{
|
||||
const auto profile{ _settings.GetProfileForArgs(newTerminalArgs) };
|
||||
@@ -86,7 +85,7 @@ namespace winrt::TerminalApp::implementation
|
||||
//
|
||||
// This call to _MakePane won't return nullptr, we already checked that
|
||||
// case above with the _maybeElevate call.
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, nullptr, existingConnection));
|
||||
_CreateNewTabFromPane(_MakePane(newTerminalArgs, nullptr));
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
@@ -148,7 +147,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// Update the taskbar progress as well. We'll raise our own
|
||||
// SetTaskbarProgress event here, to get tell the hosting
|
||||
// application to re-query this value from us.
|
||||
page->_SetTaskbarProgressHandlers(*page, nullptr);
|
||||
page->SetTaskbarProgress.raise(*page, nullptr);
|
||||
|
||||
auto profile = tab->GetFocusedProfile();
|
||||
page->_UpdateBackground(profile);
|
||||
@@ -164,23 +163,15 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (page && tab)
|
||||
{
|
||||
page->_RaiseVisualBellHandlers(nullptr, nullptr);
|
||||
page->RaiseVisualBell.raise(nullptr, nullptr);
|
||||
}
|
||||
});
|
||||
|
||||
auto tabViewItem = newTabImpl->TabViewItem();
|
||||
_tabView.TabItems().InsertAt(insertPosition, tabViewItem);
|
||||
|
||||
// Set this tab's icon to the icon from the user's profile
|
||||
if (const auto profile{ newTabImpl->GetFocusedProfile() })
|
||||
{
|
||||
if (!profile.Icon().empty())
|
||||
{
|
||||
const auto theme = _settings.GlobalSettings().CurrentTheme();
|
||||
const auto iconStyle = (theme && theme.Tab()) ? theme.Tab().IconStyle() : IconStyle::Default;
|
||||
newTabImpl->UpdateIcon(profile.Icon(), iconStyle);
|
||||
}
|
||||
}
|
||||
// Set this tab's icon to the icon from the content
|
||||
_UpdateTabIcon(*newTabImpl);
|
||||
|
||||
tabViewItem.PointerReleased({ this, &TerminalPage::_OnTabClick });
|
||||
|
||||
@@ -225,13 +216,15 @@ namespace winrt::TerminalApp::implementation
|
||||
// Arguments:
|
||||
// - pane: The pane to use as the root.
|
||||
// - insertPosition: Optional parameter to indicate the position of tab.
|
||||
void TerminalPage::_CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition)
|
||||
TerminalApp::TerminalTab TerminalPage::_CreateNewTabFromPane(std::shared_ptr<Pane> pane, uint32_t insertPosition)
|
||||
{
|
||||
if (pane)
|
||||
{
|
||||
auto newTabImpl = winrt::make_self<TerminalTab>(pane);
|
||||
_InitializeTab(newTabImpl, insertPosition);
|
||||
return *newTabImpl;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -241,11 +234,13 @@ namespace winrt::TerminalApp::implementation
|
||||
// - tab: the Tab to update the title for.
|
||||
void TerminalPage::_UpdateTabIcon(TerminalTab& tab)
|
||||
{
|
||||
if (const auto profile = tab.GetFocusedProfile())
|
||||
if (const auto content{ tab.GetActiveContent() })
|
||||
{
|
||||
const auto& icon{ content.Icon() };
|
||||
const auto theme = _settings.GlobalSettings().CurrentTheme();
|
||||
const auto iconStyle = (theme && theme.Tab()) ? theme.Tab().IconStyle() : IconStyle::Default;
|
||||
tab.UpdateIcon(profile.Icon(), iconStyle);
|
||||
|
||||
tab.UpdateIcon(icon, iconStyle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,7 +480,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// if the user manually closed all tabs.
|
||||
// Do this only if we are the last window; the monarch will notice
|
||||
// we are missing and remove us that way otherwise.
|
||||
_LastTabClosedHandlers(*this, winrt::make<LastTabClosedEventArgs>(!_maintainStateOnTabClose));
|
||||
LastTabClosed.raise(*this, winrt::make<LastTabClosedEventArgs>(!_maintainStateOnTabClose));
|
||||
}
|
||||
else if (focusedTabIndex.has_value() && focusedTabIndex.value() == gsl::narrow_cast<uint32_t>(tabIndex))
|
||||
{
|
||||
@@ -799,14 +794,6 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto index{ _GetFocusedTabIndex() })
|
||||
{
|
||||
const auto tab{ _tabs.GetAt(*index) };
|
||||
if (tab.try_as<TerminalApp::SettingsTab>())
|
||||
{
|
||||
_HandleCloseTabRequested(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -953,7 +940,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// Raise an event that our title changed
|
||||
if (_settings.GlobalSettings().ShowTitleInTitlebar())
|
||||
{
|
||||
_TitleChangedHandlers(*this, tab.Title());
|
||||
TitleChanged.raise(*this, tab.Title());
|
||||
}
|
||||
|
||||
_updateThemeColors();
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// Sometimes nested bindings do not get updated,
|
||||
// thus let's notify property changed on TabStatus when one of its properties changes
|
||||
auto item{ weakThis.get() };
|
||||
item->_PropertyChangedHandlers(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
|
||||
item->PropertyChanged.raise(*item, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"TabStatus" });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace winrt::TerminalApp::implementation
|
||||
return _tab.get();
|
||||
}
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, _PropertyChangedHandlers);
|
||||
WINRT_OBSERVABLE_PROPERTY(winrt::TerminalApp::TerminalTabStatus, TabStatus, PropertyChanged.raise);
|
||||
|
||||
private:
|
||||
winrt::weak_ref<winrt::TerminalApp::TabBase> _tab;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user