{% endif %} You can reproduce the issue remotely in OneFuzz by running the following command:
{{ repro_cmd }}
"
+ },
+ "on_duplicate": {
+ "set_state": {"Resolved": "Active", "Closed": "Active"},
+ "ado_fields": {
+ "System.IterationPath": "OS\\Future"
+ },
+ "increment": ["OSG.Watson.Telemetry14DaysInMarketHits"]
+ }
+ }
+}
diff --git a/build/Helix/OutputTestResults.ps1 b/build/Helix/OutputTestResults.ps1
index eee4c5baece..a23b456afe8 100644
--- a/build/Helix/OutputTestResults.ps1
+++ b/build/Helix/OutputTestResults.ps1
@@ -31,7 +31,7 @@ $totalTestsExecutedCount = 0
# We assume that we only have one testRun with a given name that we care about
# We only process the last testRun with a given name (based on completedDate)
-# The name of a testRun is set to the Helix queue that it was run on (e.g. windows.10.amd64.client19h1.xaml)
+# The name of a testRun is set to the Helix queue that it was run on (e.g. windows.10.amd64.client21h1.xaml)
# If we have multiple test runs on the same queue that we care about, we will need to re-visit this logic
foreach ($testRun in ($testRuns.value | Sort-Object -Property "completedDate" -Descending))
{
diff --git a/build/config/GitCheckin.json b/build/config/GitCheckin.json
new file mode 100644
index 00000000000..8bfcb203023
--- /dev/null
+++ b/build/config/GitCheckin.json
@@ -0,0 +1,24 @@
+{
+ "Branch": [
+ {
+ "collection": "microsoft",
+ "project": "OS",
+ "repo": "os.2020",
+ "name": "official/rs_wdx_dxp_windev",
+ "workitem": "38106206",
+ "CheckinFiles": [
+ {
+ "source": "WindowsTerminal.app.man",
+ "path": "/redist/mspartners/ipa/WindowsTerminal",
+ "type": "File"
+ }
+ ]
+ }
+ ],
+ "Email": [
+ {
+ "sendTo": "condev",
+ "sendOnErrorOnly": "False"
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/build/packages.config b/build/packages.config
index 34e0e10c1c9..7b2f271d521 100644
--- a/build/packages.config
+++ b/build/packages.config
@@ -2,5 +2,5 @@
-
+
diff --git a/build/pgo/Terminal.PGO.props b/build/pgo/Terminal.PGO.props
index 1e82c2305d4..55a5e39f4d8 100644
--- a/build/pgo/Terminal.PGO.props
+++ b/build/pgo/Terminal.PGO.props
@@ -1,7 +1,7 @@
$(MSBuildThisFileDirectory)..\..\packages
- $(NuGetPackageDirectory)\Microsoft.PGO-Helpers.Cpp.0.2.22
+ $(NuGetPackageDirectory)\Microsoft.Internal.PGO-Helpers.Cpp.0.2.34
@@ -20,6 +20,12 @@
$(VersionMinor)
+
+ 0
+
+
+
+
$(MSBuildThisFileDirectory)..\..\nuget.config
diff --git a/build/pipelines/ci.yml b/build/pipelines/ci.yml
index a13b7cbb58d..1c23df92487 100644
--- a/build/pipelines/ci.yml
+++ b/build/pipelines/ci.yml
@@ -38,6 +38,7 @@ stages:
- template: ./templates/build-console-audit-job.yml
parameters:
platform: x64
+
- stage: Build_x64
displayName: Build x64
dependsOn: []
@@ -61,6 +62,7 @@ stages:
- template: ./templates/build-console-ci.yml
parameters:
platform: ARM64
+
- stage: Test_x64
displayName: Test x64
dependsOn: [Build_x64]
@@ -76,6 +78,16 @@ stages:
- template: ./templates/test-console-ci.yml
parameters:
platform: x86
+
+ - stage: Helix_x64
+ displayName: Helix x64
+ dependsOn: [Build_x64]
+ condition: and(succeeded(), not(eq(variables['Build.Reason'], 'PullRequest')))
+ jobs:
+ - template: ./templates/console-ci-helix-job.yml
+ parameters:
+ platform: x64
+
- stage: Scripts
displayName: Code Health Scripts
dependsOn: []
diff --git a/build/pipelines/feature-flag-ci.yml b/build/pipelines/feature-flag-ci.yml
new file mode 100644
index 00000000000..0ca4400463d
--- /dev/null
+++ b/build/pipelines/feature-flag-ci.yml
@@ -0,0 +1,29 @@
+trigger: none
+
+pr:
+ branches:
+ include:
+ - main
+ paths:
+ include:
+ - src/features.xml
+
+variables:
+ - name: runCodesignValidationInjectionBG
+ value: false
+
+parameters:
+ - name: buildBrandings
+ type: object
+ default:
+ - Release
+ - Preview
+ # Dev is built automatically
+ # WindowsInbox does not typically build with VS.
+
+jobs:
+ - ${{ each branding in parameters.buildBrandings }}:
+ - template: ./templates/build-console-ci.yml
+ parameters:
+ platform: x64
+ branding: ${{ branding }}
diff --git a/build/pipelines/fuzz.yml b/build/pipelines/fuzz.yml
new file mode 100644
index 00000000000..b5604b5f227
--- /dev/null
+++ b/build/pipelines/fuzz.yml
@@ -0,0 +1,59 @@
+trigger:
+ batch: true
+ branches:
+ include:
+ - main
+ paths:
+ exclude:
+ - docs/*
+ - samples/*
+ - tools/*
+
+pr: none
+
+# 0.0.yyMM.dd##
+# 0.0.1904.0900
+name: 0.0.$(Date:yyMM).$(Date:dd)$(Rev:rr)
+
+stages:
+ - stage: Build_Fuzz_Config
+ displayName: Build Fuzzers
+ dependsOn: []
+ condition: succeeded()
+ jobs:
+ - template: ./templates/build-console-fuzzing.yml
+ parameters:
+ platform: x64
+ - stage: OneFuzz
+ displayName: Submit OneFuzz Job
+ dependsOn: ['Build_Fuzz_Config']
+ condition: succeeded()
+ pool:
+ vmImage: 'ubuntu-latest'
+ variables:
+ artifactName: fuzzingBuildOutput
+ jobs:
+ - job:
+ steps:
+ - task: DownloadBuildArtifacts@0
+ inputs:
+ artifactName: $(artifactName)
+ downloadPath: $(Build.ArtifactStagingDirectory)
+ - task: UsePythonVersion@0
+ inputs:
+ versionSpec: '3.x'
+ addToPath: true
+ architecture: 'x64'
+ - bash: |
+ set -ex
+ pip -q install onefuzz
+ onefuzz config --endpoint $(endpoint) --client_id $(client_id) --authority $(authority) --tenant_domain $(tenant_domain) --client_secret $(client_secret)
+ sed -i s/INSERT_PAT_HERE/$(ado_pat)/ build/Fuzz/notifications-ado.json
+ sed -i s/INSERT_ASSIGNED_HERE/$(ado_assigned_to)/ build/Fuzz/notifications-ado.json
+ displayName: Configure OneFuzz
+ - bash: |
+ onefuzz template libfuzzer basic --colocate_all_tasks --vm_count 1 --target_exe $target_exe_path --notification_config @./build/Fuzz/notifications-ado.json OpenConsole $test_name $(Build.SourceVersion) default
+ displayName: Submit OneFuzz Job
+ env:
+ target_exe_path: $(Build.ArtifactStagingDirectory)/$(artifactName)/Fuzzing/x64/test/OpenConsoleFuzzer.exe
+ test_name: WriteCharsLegacy
diff --git a/build/pipelines/release.yml b/build/pipelines/release.yml
index ea92fcab764..abe79847680 100644
--- a/build/pipelines/release.yml
+++ b/build/pipelines/release.yml
@@ -22,6 +22,10 @@ parameters:
displayName: "Run Compliance and Security Build"
type: boolean
default: true
+ - name: publishSymbolsToPublic
+ displayName: "Publish Symbols to MSDL"
+ type: boolean
+ default: true
- name: buildTerminalVPack
displayName: "Build Windows Terminal VPack"
type: boolean
@@ -48,6 +52,11 @@ parameters:
- x64
- x86
- arm64
+ - name: buildWindowsVersions
+ type: object
+ default:
+ - Win10
+ - Win11
variables:
TerminalInternalPackageVersion: "0.0.7"
@@ -64,9 +73,11 @@ jobs:
matrix:
${{ each config in parameters.buildConfigurations }}:
${{ each platform in parameters.buildPlatforms }}:
- ${{ config }}_${{ platform }}:
- BuildConfiguration: ${{ config }}
- BuildPlatform: ${{ platform }}
+ ${{ each windowsVersion in parameters.buildWindowsVersions }}:
+ ${{ config }}_${{ platform }}_${{ windowsVersion }}:
+ BuildConfiguration: ${{ config }}
+ BuildPlatform: ${{ platform }}
+ TerminalTargetWindowsVersion: ${{ windowsVersion }}
displayName: Build
timeoutInMinutes: 240
cancelTimeoutInMinutes: 1
@@ -151,6 +162,11 @@ jobs:
$Files | % { Move-Item -Verbose $_.Directory $_.Directory.Parent.Parent -EA:Ignore }
pwsh: true
+ - task: PowerShell@2
+ displayName: Copy the Context Menu Loc Resources to CascadiaPackage
+ inputs:
+ filePath: ./build/scripts/Copy-ContextMenuResourcesToCascadiaPackage.ps1
+ pwsh: true
- task: PowerShell@2
displayName: Generate NOTICE.html from NOTICE.md
inputs:
@@ -158,13 +174,17 @@ jobs:
arguments: -MarkdownNoticePath .\NOTICE.md -OutputPath .\src\cascadia\CascadiaPackage\NOTICE.html
pwsh: true
- ${{ if eq(parameters.buildTerminal, true) }}:
+ - pwsh: |-
+ ./build/scripts/Patch-ManifestsToWindowsVersion.ps1 -NewWindowsVersion "10.0.22000.0"
+ displayName: Update manifest target version to Win11 (if necessary)
+ condition: and(succeeded(), eq(variables['TerminalTargetWindowsVersion'], 'Win11'))
- task: VSBuild@1
displayName: Build solution **\OpenConsole.sln
condition: true
inputs:
solution: '**\OpenConsole.sln'
vsVersion: 16.0
- msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /t:Terminal\CascadiaPackage;Terminal\WindowsTerminalUniversal /p:WindowsTerminalReleaseBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
+ msbuildArgs: /p:WindowsTerminalOfficialBuild=true /p:WindowsTerminalBranding=${{ parameters.branding }};PGOBuildMode=${{ parameters.pgoBuildMode }} /t:Terminal\CascadiaPackage /p:WindowsTerminalReleaseBuild=true /bl:$(Build.SourcesDirectory)\msbuild.binlog
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
clean: true
@@ -175,7 +195,7 @@ jobs:
continueOnError: True
inputs:
PathtoPublish: $(Build.SourcesDirectory)\msbuild.binlog
- ArtifactName: binlog-$(BuildPlatform)
+ ArtifactName: binlog-$(BuildPlatform)-$(TerminalTargetWindowsVersion)
- task: PowerShell@2
displayName: Check MSIX for common regressions
inputs:
@@ -238,7 +258,7 @@ jobs:
displayName: Publish Artifact (appx)
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory)/appx
- ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)
+ ArtifactName: appx-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
- ${{ if eq(parameters.buildWPF, true) }}:
- task: CopyFiles@2
displayName: Copy PublicTerminalCore.dll to Artifacts
@@ -256,7 +276,7 @@ jobs:
condition: and(succeeded(), ne(variables['BuildPlatform'], 'arm64'))
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory)/wpf
- ArtifactName: wpf-dll-$(BuildPlatform)-$(BuildConfiguration)
+ ArtifactName: wpf-dll-$(BuildPlatform)-$(BuildConfiguration)-$(TerminalTargetWindowsVersion)
- task: PublishSymbols@2
displayName: Publish symbols path
@@ -274,6 +294,11 @@ jobs:
- ${{ if eq(parameters.buildTerminal, true) }}:
- job: BundleAndSign
+ strategy:
+ matrix:
+ ${{ each windowsVersion in parameters.buildWindowsVersions }}:
+ ${{ windowsVersion }}:
+ TerminalTargetWindowsVersion: ${{ windowsVersion }}
displayName: Create and sign AppX/MSIX bundles
dependsOn: Build
steps:
@@ -286,20 +311,16 @@ jobs:
displayName: Package ES - Setup Build
inputs:
disableOutputRedirect: true
- - task: DownloadBuildArtifacts@0
- displayName: Download Artifacts (*.appx, *.msix)
- inputs:
- downloadType: specific
- itemPattern: >-
- **/*.msix
-
- **/*.appx
- extractTars: false
+ - ${{ each platform in parameters.buildPlatforms }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Artifacts ${{ platform }} $(TerminalTargetWindowsVersion)
+ inputs:
+ artifactName: appx-${{ platform }}-Release-$(TerminalTargetWindowsVersion)
- task: PowerShell@2
displayName: Create WindowsTerminal*.msixbundle
inputs:
filePath: build\scripts\Create-AppxBundle.ps1
- arguments: -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion 0.0.0.0 -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminal_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
+ arguments: -InputPath "$(System.ArtifactsDirectory)" -ProjectName CascadiaPackage -BundleVersion 0.0.0.0 -OutputPath "$(System.ArtifactsDirectory)\Microsoft.WindowsTerminal_$(TerminalTargetWindowsVersion)_$(XES_APPXMANIFESTVERSION)_8wekyb3d8bbwe.msixbundle"
- task: EsrpCodeSigning@1
displayName: Submit *.msixbundle to ESRP for code signing
inputs:
@@ -334,11 +355,12 @@ jobs:
"ToolVersion": "1.0"
}
]
+
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: appxbundle-signed'
inputs:
PathtoPublish: $(System.ArtifactsDirectory)
- ArtifactName: appxbundle-signed
+ ArtifactName: appxbundle-signed-$(TerminalTargetWindowsVersion)
- ${{ if eq(parameters.buildWPF, true) }}:
- job: PackageAndSignWPF
@@ -362,14 +384,14 @@ jobs:
- task: DownloadBuildArtifacts@0
displayName: Download x86 PublicTerminalCore
inputs:
- artifactName: wpf-dll-x86-$(BuildConfiguration)
+ artifactName: wpf-dll-x86-$(BuildConfiguration)-Win10
itemPattern: '**/*.dll'
downloadPath: bin\Win32\$(BuildConfiguration)\
extractTars: false
- task: DownloadBuildArtifacts@0
displayName: Download x64 PublicTerminalCore
inputs:
- artifactName: wpf-dll-x64-$(BuildConfiguration)
+ artifactName: wpf-dll-x64-$(BuildConfiguration)-Win10
itemPattern: '**/*.dll'
downloadPath: bin\x64\$(BuildConfiguration)\
extractTars: false
@@ -451,6 +473,71 @@ jobs:
PathtoPublish: $(Build.ArtifactStagingDirectory)\nupkg
ArtifactName: wpf-nupkg-$(BuildConfiguration)
+- ${{ if eq(parameters.publishSymbolsToPublic, true) }}:
+ - job: PublishSymbols
+ displayName: Publish Symbols
+ dependsOn: BundleAndSign
+ steps:
+ - checkout: self
+ clean: true
+ fetchDepth: 1
+ submodules: true
+ - task: PkgESSetupBuild@12
+ displayName: Package ES - Setup Build
+
+ # Download the appx-PLATFORM-CONFIG-VERSION artifact for every platform/version combo
+ - ${{ each platform in parameters.buildPlatforms }}:
+ - ${{ each windowsVersion in parameters.buildWindowsVersions }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Symbols ${{ platform }} ${{ windowsVersion }}
+ inputs:
+ artifactName: appx-${{ platform }}-Release-${{ windowsVersion }}
+
+ # It seems easier to do this -- download every appxsym -- then enumerate all the PDBs in the build directory for the
+ # public symbol push. Otherwise, we would have to list all of the PDB files one by one.
+ - pwsh: |-
+ mkdir $(Build.SourcesDirectory)/appxsym-temp
+ Get-ChildItem "$(System.ArtifactsDirectory)" -Filter *.appxsym -Recurse | % {
+ $src = $_.FullName
+ $dest = Join-Path "$(Build.SourcesDirectory)/appxsym-temp/" $_.Name
+
+ mkdir $dest
+ Write-Host "Extracting $src to $dest..."
+ tar -x -v -f $src -C $dest
+ }
+ displayName: Extract symbols for public consumption
+
+ # Pull the Windows SDK for the developer tools like the debuggers so we can index sources later
+ - template: .\templates\install-winsdk-steps.yml
+ - task: PowerShell@2
+ displayName: Source Index PDBs (the public ones)
+ inputs:
+ filePath: build\scripts\Index-Pdbs.ps1
+ arguments: -SearchDir '$(Build.SourcesDirectory)/appxsym-temp' -SourceRoot '$(Build.SourcesDirectory)' -recursive -Verbose -CommitId $(Build.SourceVersion)
+
+ # Publish the app symbols to the public MSDL symbol server
+ # accessible via https://msdl.microsoft.com/download/symbols
+ - task: PublishSymbols@2
+ displayName: 'Publish app symbols to MSDL'
+ inputs:
+ symbolsFolder: '$(Build.SourcesDirectory)/appxsym-temp'
+ searchPattern: '**/*.pdb'
+ SymbolsMaximumWaitTime: 30
+ SymbolServerType: 'TeamServices'
+ SymbolsProduct: 'Windows Terminal Application Binaries'
+ SymbolsVersion: '$(XES_APPXMANIFESTVERSION)'
+ # The ADO task does not support indexing of GitHub sources.
+ indexSources: false
+ detailedLog: true
+ # There is a bug which causes this task to fail if LIB includes an inaccessible path (even though it does not depend on it).
+ # To work around this issue, we just force LIB to be any dir that we know exists.
+ # Copied from https://github.com/microsoft/icu/blob/f869c214adc87415dfe751d81f42f1bca55dcf5f/build/azure-nuget.yml#L564-L583
+ env:
+ LIB: $(Build.SourcesDirectory)
+ ArtifactServices_Symbol_AccountName: microsoftpublicsymbols
+ ArtifactServices_Symbol_PAT: $(ADO_microsoftpublicsymbols_PAT)
+
+
- ${{ if eq(parameters.buildTerminalVPack, true) }}:
- job: VPack
displayName: Create Windows vPack
@@ -465,7 +552,7 @@ jobs:
- task: DownloadBuildArtifacts@0
displayName: Download Build Artifacts
inputs:
- artifactName: appxbundle-signed
+ artifactName: appxbundle-signed-Win11
extractTars: false
- task: PowerShell@2
displayName: Rename and stage packages for vpack
@@ -474,7 +561,7 @@ jobs:
script: >-
# Rename to known/fixed name for Windows build system
- Get-ChildItem Microsoft.WindowsTerminal_*.msixbundle | Rename-Item -NewName { 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle' }
+ Get-ChildItem Microsoft.WindowsTerminal_Win11_*.msixbundle | Rename-Item -NewName { 'Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle' }
# Create vpack directory and place item inside
@@ -489,7 +576,18 @@ jobs:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
sourceDirectory: $(System.ArtifactsDirectory)\appxbundle-signed\WindowsTerminal.app
- description: Windows Terminal pre-install application
+ description: VPack for the Windows Terminal Application
pushPkgName: WindowsTerminal.app
- owner: condev
+ owner: conhost
+ - task: PublishPipelineArtifact@1
+ displayName: 'Copy VPack Manifest to Drop'
+ inputs:
+ targetPath: $(XES_VPACKMANIFESTDIRECTORY)
+ artifactName: VPackManifest
+ - task: PkgESFCIBGit@12
+ displayName: 'Submit VPack Manifest to Windows'
+ inputs:
+ configPath: '$(Build.SourcesDirectory)\build\config\GitCheckin.json'
+ artifactsDirectory: $(XES_VPACKMANIFESTDIRECTORY)
+ prTimeOut: 5
...
diff --git a/build/pipelines/templates/build-console-ci.yml b/build/pipelines/templates/build-console-ci.yml
index 0ff8b6b5406..45d6bd4267e 100644
--- a/build/pipelines/templates/build-console-ci.yml
+++ b/build/pipelines/templates/build-console-ci.yml
@@ -1,16 +1,16 @@
parameters:
configuration: 'Release'
+ branding: 'Dev'
platform: ''
additionalBuildArguments: ''
- minimumExpectedTestsExecutedCount: 10 # Sanity check for minimum expected tests to be reported
- rerunPassesRequiredToAvoidFailure: 5
jobs:
-- job: Build${{ parameters.platform }}${{ parameters.configuration }}
- displayName: Build ${{ parameters.platform }} ${{ parameters.configuration }}
+- job: Build${{ parameters.platform }}${{ parameters.configuration }}${{ parameters.branding }}
+ displayName: Build ${{ parameters.platform }} ${{ parameters.configuration }} ${{ parameters.branding }}
variables:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
+ WindowsTerminalBranding: ${{ parameters.branding }}
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
@@ -28,21 +28,3 @@ jobs:
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: 'Component Detection'
condition: and(succeededOrFailed(), not(eq(variables['Build.Reason'], 'PullRequest')))
-
-- template: helix-runtests-job.yml
- parameters:
- name: 'RunTestsInHelix'
- dependsOn: Build${{ parameters.platform }}${{ parameters.configuration }}
- condition: and(succeeded(), and(eq('${{ parameters.platform }}', 'x64'), not(eq(variables['Build.Reason'], 'PullRequest'))))
- testSuite: 'DevTestSuite'
- platform: ${{ parameters.platform }}
- configuration: ${{ parameters.configuration }}
- rerunPassesRequiredToAvoidFailure: ${{ parameters.rerunPassesRequiredToAvoidFailure }}
-
-- template: helix-processtestresults-job.yml
- parameters:
- dependsOn:
- - RunTestsInHelix
- condition: and(succeededOrFailed(), and(eq('${{ parameters.platform }}', 'x64'), not(eq(variables['Build.Reason'], 'PullRequest'))))
- rerunPassesRequiredToAvoidFailure: ${{ parameters.rerunPassesRequiredToAvoidFailure }}
- minimumExpectedTestsExecutedCount: ${{ parameters.minimumExpectedTestsExecutedCount }}
\ No newline at end of file
diff --git a/build/pipelines/templates/build-console-fuzzing.yml b/build/pipelines/templates/build-console-fuzzing.yml
new file mode 100644
index 00000000000..1c8dee82cc2
--- /dev/null
+++ b/build/pipelines/templates/build-console-fuzzing.yml
@@ -0,0 +1,114 @@
+parameters:
+ configuration: 'Fuzzing'
+ platform: ''
+ additionalBuildArguments: ''
+
+jobs:
+- job: Build${{ parameters.platform }}${{ parameters.configuration }}
+ displayName: Build ${{ parameters.platform }} ${{ parameters.configuration }}
+ variables:
+ BuildConfiguration: ${{ parameters.configuration }}
+ BuildPlatform: ${{ parameters.platform }}
+ pool:
+ ${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
+ name: WinDevPoolOSS-L
+ ${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
+ name: WinDevPool-L
+ demands: ImageOverride -equals WinDevVS16-latest
+
+ steps:
+ - checkout: self
+ submodules: true
+ clean: true
+
+ - task: NuGetToolInstaller@0
+ displayName: 'Use NuGet 5.2.0'
+ inputs:
+ versionSpec: 5.2.0
+
+ # In the Microsoft Azure DevOps tenant, NuGetCommand is ambiguous.
+ # This should be `task: NuGetCommand@2`
+ - task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
+ displayName: Restore NuGet packages for solution
+ inputs:
+ command: restore
+ feedsToUse: config
+ configPath: NuGet.config
+ restoreSolution: OpenConsole.sln
+ restoreDirectory: '$(Build.SourcesDirectory)\packages'
+
+ - task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
+ displayName: Restore NuGet packages for extraneous build actions
+ inputs:
+ command: restore
+ feedsToUse: config
+ configPath: NuGet.config
+ restoreSolution: build/packages.config
+ restoreDirectory: '$(Build.SourcesDirectory)\packages'
+
+ # The environment variable VCToolsInstallDir isn't defined on lab machines, so we need to retrieve it ourselves.
+ - script: |
+ "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -Latest -requires Microsoft.Component.MSBuild -property InstallationPath > %TEMP%\vsinstalldir.txt
+ set /p _VSINSTALLDIR15=<%TEMP%\vsinstalldir.txt
+ del %TEMP%\vsinstalldir.txt
+ call "%_VSINSTALLDIR15%\Common7\Tools\VsDevCmd.bat"
+ echo VCToolsInstallDir = %VCToolsInstallDir%
+ echo ##vso[task.setvariable variable=VCToolsInstallDir]%VCToolsInstallDir%
+ displayName: 'Retrieve VC tools directory'
+
+ - task: VSBuild@1
+ displayName: 'Build solution **\OpenConsole.sln'
+ inputs:
+ solution: '**\OpenConsole.sln'
+ vsVersion: 16.0
+ platform: '$(BuildPlatform)'
+ configuration: '$(BuildConfiguration)'
+ msbuildArgs: "${{ parameters.additionalBuildArguments }}"
+ clean: true
+ maximumCpuCount: true
+
+ - task: PowerShell@2
+ displayName: 'Rationalize build platform'
+ inputs:
+ targetType: inline
+ script: |
+ $Arch = "$(BuildPlatform)"
+ If ($Arch -Eq "x86") { $Arch = "Win32" }
+ Write-Host "##vso[task.setvariable variable=RationalizedBuildPlatform]${Arch}"
+
+ - task: CopyFiles@2
+ displayName: 'Copy result logs to Artifacts'
+ inputs:
+ Contents: |
+ **/*.wtl
+ **/*onBuildMachineResults.xml
+ ${{ parameters.testLogPath }}
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/$(BuildConfiguration)/$(BuildPlatform)/test'
+ OverWrite: true
+ flattenFolders: true
+
+ - task: CopyFiles@2
+ displayName: 'Copy outputs needed for test runs to Artifacts'
+ inputs:
+ Contents: |
+ $(Build.SourcesDirectory)/bin/$(RationalizedBuildPlatform)/$(BuildConfiguration)/*.exe
+ $(Build.SourcesDirectory)/bin/$(RationalizedBuildPlatform)/$(BuildConfiguration)/*.dll
+ $(Build.SourcesDirectory)/bin/$(RationalizedBuildPlatform)/$(BuildConfiguration)/*.xml
+ **/Microsoft.VCLibs.*.appx
+ **/TestHostApp/*.exe
+ **/TestHostApp/*.dll
+ **/TestHostApp/*.xml
+ !**/*.pdb
+ !**/*.ipdb
+ !**/*.obj
+ !**/*.pch
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/$(BuildConfiguration)/$(BuildPlatform)/test'
+ OverWrite: true
+ flattenFolders: true
+ condition: succeeded()
+
+ - task: PublishBuildArtifacts@1
+ displayName: 'Publish All Build Artifacts'
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)'
+ ArtifactName: 'fuzzingBuildOutput'
\ No newline at end of file
diff --git a/build/pipelines/templates/build-console-steps.yml b/build/pipelines/templates/build-console-steps.yml
index 03141ac5f81..89e091ff736 100644
--- a/build/pipelines/templates/build-console-steps.yml
+++ b/build/pipelines/templates/build-console-steps.yml
@@ -126,7 +126,7 @@ steps:
displayName: 'Publish All Build Artifacts'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
- ArtifactName: 'drop'
+ ArtifactName: 'drop'
- task: CopyFiles@2
displayName: 'Copy PGO databases needed for PGO instrumentation run'
@@ -147,7 +147,7 @@ steps:
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: binlog'
- condition: failed()
+ condition: always()
continueOnError: True
inputs:
PathtoPublish: $(Build.SourcesDirectory)\msbuild.binlog
diff --git a/build/pipelines/templates/console-ci-helix-job.yml b/build/pipelines/templates/console-ci-helix-job.yml
new file mode 100644
index 00000000000..07476712a02
--- /dev/null
+++ b/build/pipelines/templates/console-ci-helix-job.yml
@@ -0,0 +1,25 @@
+parameters:
+ configuration: 'Release'
+ platform: ''
+ minimumExpectedTestsExecutedCount: 10 # Sanity check for minimum expected tests to be reported
+ rerunPassesRequiredToAvoidFailure: 5
+
+jobs:
+- template: helix-runtests-job.yml
+ parameters:
+ name: 'RunTestsInHelix'
+ # We're not setting dependsOn as we want to rely on the "stage" dependency above us
+ testSuite: 'DevTestSuite'
+ platform: ${{ parameters.platform }}
+ configuration: ${{ parameters.configuration }}
+ rerunPassesRequiredToAvoidFailure: ${{ parameters.rerunPassesRequiredToAvoidFailure }}
+
+- template: helix-processtestresults-job.yml
+ parameters:
+ dependsOn:
+ - RunTestsInHelix
+ # the default condition is succeededOrFailed(), and the "stage" condition ensures we only run as needed
+ platform: ${{ parameters.platform }}
+ configuration: ${{ parameters.configuration }}
+ rerunPassesRequiredToAvoidFailure: ${{ parameters.rerunPassesRequiredToAvoidFailure }}
+ minimumExpectedTestsExecutedCount: ${{ parameters.minimumExpectedTestsExecutedCount }}
diff --git a/build/pipelines/templates/helix-processtestresults-job.yml b/build/pipelines/templates/helix-processtestresults-job.yml
index 1e5ff3c73e5..bd8e967de92 100644
--- a/build/pipelines/templates/helix-processtestresults-job.yml
+++ b/build/pipelines/templates/helix-processtestresults-job.yml
@@ -8,6 +8,7 @@ parameters:
jobs:
- job: ProcessTestResults
+ displayName: Process Helix Results ${{ parameters.platform }} ${{ parameters.configuration }}
condition: ${{ parameters.condition }}
dependsOn: ${{ parameters.dependsOn }}
pool:
diff --git a/build/pipelines/templates/helix-runtests-job.yml b/build/pipelines/templates/helix-runtests-job.yml
index 042c54c12ee..853125d709a 100644
--- a/build/pipelines/templates/helix-runtests-job.yml
+++ b/build/pipelines/templates/helix-runtests-job.yml
@@ -14,11 +14,12 @@ parameters:
platform: ''
# if 'useBuildOutputFromBuildId' is set, we will default to using a build from this pipeline:
useBuildOutputFromPipeline: $(System.DefinitionId)
- openHelixTargetQueues: 'windows.10.amd64.client19h1.open.xaml'
- closedHelixTargetQueues: 'windows.10.amd64.client19h1.xaml'
+ openHelixTargetQueues: 'windows.10.amd64.client21h1.open.xaml'
+ closedHelixTargetQueues: 'windows.10.amd64.client21h1.xaml'
jobs:
- job: ${{ parameters.name }}
+ displayName: Submit Helix ${{ parameters.platform }} ${{ parameters.configuration }}
dependsOn: ${{ parameters.dependsOn }}
condition: ${{ parameters.condition }}
pool:
diff --git a/build/pipelines/templates/pgo-merge-pgd-job.yml b/build/pipelines/templates/pgo-merge-pgd-job.yml
index 930472f5822..8a1c2423113 100644
--- a/build/pipelines/templates/pgo-merge-pgd-job.yml
+++ b/build/pipelines/templates/pgo-merge-pgd-job.yml
@@ -55,7 +55,7 @@ jobs:
solution: $(Build.SourcesDirectory)\OpenConsole.sln
platform: $(buildPlatform)
configuration: $(buildConfiguration)
- msbuildArguments: '/t:MergePGOCounts /p:PGDPath=$(pgoArtifactsPath)\$(buildPlatform) /p:PGCRootPath=$(pgoArtifactsPath)\$(buildPlatform)'
+ msbuildArguments: '/t:MergePGOCounts /p:PGOBuildMode=Instrument /p:PGDPath=$(pgoArtifactsPath)\$(buildPlatform) /p:PGCRootPath=$(pgoArtifactsPath)\$(buildPlatform)'
- task: CopyFiles@2
displayName: 'Copy merged pgd to artifact staging'
@@ -67,4 +67,4 @@ jobs:
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: $(Build.ArtifactStagingDirectory)
- artifactName: ${{ parameters.pgoArtifact }}
\ No newline at end of file
+ artifactName: ${{ parameters.pgoArtifact }}
diff --git a/build/pipelines/templates/test-console-ci.yml b/build/pipelines/templates/test-console-ci.yml
index 25c28ac5235..542edef2916 100644
--- a/build/pipelines/templates/test-console-ci.yml
+++ b/build/pipelines/templates/test-console-ci.yml
@@ -2,8 +2,6 @@ parameters:
configuration: 'Release'
platform: ''
additionalBuildArguments: ''
- minimumExpectedTestsExecutedCount: 10 # Sanity check for minimum expected tests to be reported
- rerunPassesRequiredToAvoidFailure: 5
artifactName: 'drop'
testLogPath: '$(Build.BinariesDirectory)\$(BuildPlatform)\$(BuildConfiguration)\testsOnBuildMachine.wtl'
diff --git a/build/scripts/Copy-ContextMenuResourcesToCascadiaPackage.ps1 b/build/scripts/Copy-ContextMenuResourcesToCascadiaPackage.ps1
new file mode 100644
index 00000000000..8111b3fc66e
--- /dev/null
+++ b/build/scripts/Copy-ContextMenuResourcesToCascadiaPackage.ps1
@@ -0,0 +1,34 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT license.
+
+$LocalizationsFromContextMenu = Get-ChildItem ./src/cascadia/TerminalApp/Resources -Recurse -Filter ContextMenu.resw
+$Languages = [System.Collections.HashTable]::New()
+$LocalizationsFromContextMenu | ForEach-Object {
+ $Languages[$_.Directory.Name] = $_
+}
+
+ForEach ($pair in $Languages.GetEnumerator()) {
+ $LanguageDir = "./src/cascadia/CascadiaPackage/Resources/$($pair.Key)"
+ $ResPath = "$LanguageDir/Resources.resw"
+ $PreexistingResw = Get-Item $ResPath -EA:Ignore
+ If ($null -eq $PreexistingResw) {
+ Write-Host "Copying $($pair.Value.FullName) to $ResPath"
+ New-Item -type Directory $LanguageDir -EA:Ignore
+ Copy-Item $pair.Value.FullName $ResPath
+ } Else {
+ # Merge Them!
+ Write-Host "Merging $($pair.Value.FullName) into $ResPath"
+ $existingXml = [xml](Get-Content $PreexistingResw.FullName)
+ $newXml = [xml](Get-Content $pair.Value.FullName)
+ $newDataKeys = $newXml.root.data.name
+ $existingXml.root.data | % {
+ If ($_.name -in $newDataKeys) {
+ $null = $existingXml.root.RemoveChild($_)
+ }
+ }
+ $newXml.root.data | % {
+ $null = $existingXml.root.AppendChild($existingXml.ImportNode($_, $true))
+ }
+ $existingXml.Save($PreexistingResw.FullName)
+ }
+}
diff --git a/build/scripts/Patch-ManifestsToWindowsVersion.ps1 b/build/scripts/Patch-ManifestsToWindowsVersion.ps1
new file mode 100644
index 00000000000..fe86f24fd8c
--- /dev/null
+++ b/build/scripts/Patch-ManifestsToWindowsVersion.ps1
@@ -0,0 +1,14 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT license.
+
+Param(
+ [string]$NewWindowsVersion = "10.0.22000.0"
+)
+
+Get-ChildItem src/cascadia/CascadiaPackage -Recurse -Filter *.appxmanifest | ForEach-Object {
+ $xml = [xml](Get-Content $_.FullName)
+ $xml.Package.Dependencies.TargetDeviceFamily | Where-Object Name -Like "Windows*" | ForEach-Object {
+ $_.MinVersion = $NewWindowsVersion
+ }
+ $xml.Save($_.FullName)
+}
diff --git a/common.openconsole.props b/common.openconsole.props
index e521ad61996..400555dbdd5 100644
--- a/common.openconsole.props
+++ b/common.openconsole.props
@@ -10,4 +10,18 @@
$(MSBuildThisFileDirectory)
+
+
+ 2.7.0-prerelease.210913003
+
+ 2.7.0
+
+
diff --git a/custom.props b/custom.props
index 23f7ff5aa82..aab0b65870b 100644
--- a/custom.props
+++ b/custom.props
@@ -2,10 +2,22 @@
+
+ $([MSBuild]::Add($(VersionBuildRevision), 1))
+
true
- 2021
+ 20221
- 13
+ 14Windows Terminal
diff --git a/dep/Console/conapi.h b/dep/Console/conapi.h
index 84535ec6800..e3667083032 100644
--- a/dep/Console/conapi.h
+++ b/dep/Console/conapi.h
@@ -1,5 +1,6 @@
/*++
-Copyright (c) Microsoft Corporation
+Copyright (c) Microsoft Corporation.
+Licensed under the MIT license.
Module Name:
- conapi.h
diff --git a/dep/Console/condrv.h b/dep/Console/condrv.h
index b5654d98bbd..d2d435ca5c5 100644
--- a/dep/Console/condrv.h
+++ b/dep/Console/condrv.h
@@ -1,6 +1,7 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
+Licensed under the MIT license.
Module Name:
diff --git a/dep/Console/conmsgl1.h b/dep/Console/conmsgl1.h
index 41ef9c74108..ce83e966415 100644
--- a/dep/Console/conmsgl1.h
+++ b/dep/Console/conmsgl1.h
@@ -1,6 +1,7 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
+Licensed under the MIT license.
Module Name:
diff --git a/dep/Console/conmsgl2.h b/dep/Console/conmsgl2.h
index d1abb749ab5..2ab5d65bce2 100644
--- a/dep/Console/conmsgl2.h
+++ b/dep/Console/conmsgl2.h
@@ -1,6 +1,7 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
+Licensed under the MIT license.
Module Name:
diff --git a/dep/Console/conmsgl3.h b/dep/Console/conmsgl3.h
index 9e3d8e65453..9533c83d792 100644
--- a/dep/Console/conmsgl3.h
+++ b/dep/Console/conmsgl3.h
@@ -1,6 +1,7 @@
/*++
-Copyright (c) 1985 - 1999, Microsoft Corporation
+Copyright (c) 1985 - 1999, Microsoft Corporation.
+Licensed under the MIT license.
Module Name:
diff --git a/dep/Console/ntcon.h b/dep/Console/ntcon.h
index 9b196672883..201ff69a05e 100644
--- a/dep/Console/ntcon.h
+++ b/dep/Console/ntcon.h
@@ -1,5 +1,6 @@
//
// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license.
//
#ifndef _NTCON_
#define _NTCON_
diff --git a/dep/Console/winconp.h b/dep/Console/winconp.h
index eb05f329307..23fba76c144 100644
--- a/dep/Console/winconp.h
+++ b/dep/Console/winconp.h
@@ -1,3 +1,7 @@
+/*++
+Copyright (c) Microsoft Corporation.
+Licensed under the MIT license.
+--*/
#ifndef _WINCONP_
#define _WINCONP_
diff --git a/dep/NT/ntioapi_x.h b/dep/NT/ntioapi_x.h
index d89e0fc888a..abbf5ce6d30 100644
--- a/dep/NT/ntioapi_x.h
+++ b/dep/NT/ntioapi_x.h
@@ -1,3 +1,8 @@
+/*++
+Copyright (c) Microsoft Corporation.
+Licensed under the MIT license.
+--*/
+
#pragma once
#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
diff --git a/dep/Win32K/winuserp.h b/dep/Win32K/winuserp.h
index faea9854f33..4174fce5399 100644
--- a/dep/Win32K/winuserp.h
+++ b/dep/Win32K/winuserp.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT license.
+ *
* Reserved console space.
*
* This was moved from the console code so that we can localize it
diff --git a/doc/Niksa.md b/doc/Niksa.md
index c4c7e479885..c3f8a1fa1af 100644
--- a/doc/Niksa.md
+++ b/doc/Niksa.md
@@ -163,7 +163,7 @@ Given that we're using Xaml islands to host a modern UI and stitching a DirectX
Now, the obvious followup question is _"why can't you have one elevated connection in a tab next to a non-elevated connection?"_ This is where @sba923 should pick up reading (:smile:). I'm probably going to cover some things that you (@robomac) know already.
-[2] When you have two windows on the same desktop in the same window station, they can communicate with eachother. I can use `SendKeys` easily through `WScript.Shell` to send keyboard input to any window that the shell can see.
+[2] When you have two windows on the same desktop in the same window station, they can communicate with each other. I can use `SendKeys` easily through `WScript.Shell` to send keyboard input to any window that the shell can see.
Running a process elevated _severs_ that connection. The shell can't see the elevated window. No other program at the same integrity level as the shell can see the elevated window. Even if it has its window handle, it can't really interact with it. This is also why you can't drag/drop from explorer into notepad if notepad is running elevated. Only another elevated process can interact with another elevated window.
diff --git a/doc/cascadia/Unittesting-CppWinRT-Xaml.md b/doc/cascadia/Unittesting-CppWinRT-Xaml.md
index 4160e035e2e..9ddcae046a0 100644
--- a/doc/cascadia/Unittesting-CppWinRT-Xaml.md
+++ b/doc/cascadia/Unittesting-CppWinRT-Xaml.md
@@ -268,7 +268,7 @@ this:
```
-Again, verify the correct paths to your dependant C++/WinRT dlls, as they may be
+Again, verify the correct paths to your dependent C++/WinRT dlls, as they may be
different than the above
#### Activating the manifest from TAEF
diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json
index 437cc09c861..b7abd93b661 100644
--- a/doc/cascadia/profiles.schema.json
+++ b/doc/cascadia/profiles.schema.json
@@ -1709,7 +1709,7 @@
},
"startOnUserLogin": {
"default": false,
- "description": "When set to true, this enables the launch of Windows Terminal at startup. Setting this to false will disable the startup task entry. If the Windows Terminal startup task entry is disabled either by org policy or by user action this setting will have no effect.",
+ "description": "When set to true, this enables the launch of Terminal at startup. Setting this to false will disable the startup task entry. If the Terminal startup task entry is disabled either by org policy or by user action this setting will have no effect.",
"type": "boolean"
},
"firstWindowPreference": {
@@ -1761,7 +1761,7 @@
},
"useAcrylicInTabRow": {
"default": false,
- "description": "When set to true, the tab row will have an acrylic background with 50% opacity.",
+ "description": "When set to true, the tab row will have an acrylic material background with 50% opacity.",
"type": "boolean"
},
"actions": {
@@ -2059,6 +2059,11 @@
"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"
},
+ "experimental.useAtlasEngine": {
+ "description": "Enable using the experimental new rendering engine for this profile. This is an experimental feature, and its continued existence is not guaranteed.",
+ "type": "boolean",
+ "default": false
+ },
"fontFace": {
"default": "Cascadia Mono",
"description": "[deprecated] Define 'face' within the 'font' object instead.",
@@ -2219,7 +2224,7 @@
},
"useAcrylic": {
"default": false,
- "description": "When set to true, the window will have an acrylic background. When set to false, the window will have a plain, untextured background.",
+ "description": "When set to true, the window will have an acrylic material background. When set to false, the window will have a plain, untextured background.",
"type": "boolean"
}
},
diff --git a/doc/fuzzing.md b/doc/fuzzing.md
new file mode 100644
index 00000000000..5d855f5fd17
--- /dev/null
+++ b/doc/fuzzing.md
@@ -0,0 +1,60 @@
+# Fuzzing
+
+## Setting up a fuzzer locally
+
+OpenConsole can be built with a `Fuzzing` configuration. To set up a fuzzer, you'll need an `LLVMFuzzerTestOneInput` function. This serves as a way for the fuzzer to attach itself and inject tests into your fuzz target.
+
+To build the fuzzer locally, build the OpenConsole solution in the `Fuzzing` configuration. This should output an executable that runs the fuzzer on the provided test case. In the case of PR #9604, the desired executable is located at `bin\x64\Fuzzing\OpenConsoleFuzzer.exe`.
+
+### Resources
+- [LibFuzzer Docs](https://www.llvm.org/docs/LibFuzzer.html)
+- [#9604](https://github.com/microsoft/terminal/pull/9604)
+
+## Setting up OneFuzz
+
+OneFuzz allows us to run our fuzzers in CI and be alerted of new bugs found in this endeavor.
+
+### Installing OneFuzz
+
+You can download the latest OneFuzz CLI on their [releases page](https://github.com/microsoft/onefuzz/releases).
+
+### Configuring OneFuzz
+
+To run OneFuzz locally, you'll need to configure its endpoint, client ID, and client secret. Windows has a preset configuration available; this can be found at [this tutorial](https://www.osgwiki.com/wiki/Fuzzing_Service_-_Azure_Edge_and_Platform#Configure_OneFuzz_CLI) on osgwiki.
+
+
+
+`onefuzz config --endpoint $(endpoint) --client_id $(client_id) --authority $(authority) --tenant_domain $(tenant_domain)`
+
+**NOTE**: Our pipeline is already set up with these variables, so you don't need to worry about this when running this on Azure DevOps.
+
+### Running a job on OneFuzz
+
+You should now be able to run a job using the following command:
+
+`onefuzz template libfuzzer basic --target_exe `
+
+- `project`: the name of the project
+- `name`: the name of the test
+- `build`: the identifier for the build (i.e. commit SHA1)
+- `pool`: the VM pool to run this on
+- `exe_path`: the fuzzer executable output from building your project
+
+This should also output more information (i.e. job ID) about the newly created job in a JSON format.
+
+### Enabling notifications
+
+**NOTE**: Our pipeline is already set up with this functionality. However, here is a quick guide on how to get it set up and modify it to our liking.
+
+OneFuzz supports multiple notification systems at once including MS Teams and Azure DevOps. See the resources below to learn more about setting these up.
+
+Our pipeline has been set up to create Azure DevOps work items.
+
+### Resources
+- [OneFuzz GitHub](https://github.com/microsoft/onefuzz)
+ - [Getting started using OneFuzz](https://github.com/microsoft/onefuzz/blob/main/docs/getting-started.md)
+ - [Releases Page](https://github.com/microsoft/onefuzz/releases)
+- [Notifications](https://github.com/microsoft/onefuzz/blob/main/docs/notifications.md)
+ - [MS Teams](https://github.com/microsoft/onefuzz/blob/main/docs/notifications/teams.md)
+ - [Azure DevOps](https://github.com/microsoft/onefuzz/blob/main/docs/notifications/ado.md)
+- [OSG Wiki - OneFuzz](https://www.osgwiki.com/wiki/Fuzzing_Service_-_Azure_Edge_and_Platform)
\ No newline at end of file
diff --git a/doc/specs/#1790 - Font features and axes-spec.md b/doc/specs/#1790 - Font features and axes-spec.md
index 63b56230361..fd0f59bb7e9 100644
--- a/doc/specs/#1790 - Font features and axes-spec.md
+++ b/doc/specs/#1790 - Font features and axes-spec.md
@@ -74,7 +74,7 @@ Should not affect security.
### Reliability
-Aside from additional parsing required for the settings file (which inherently offers more locations for parsing to fail), we need to be careful about badly formed/non-existant feature tags or axes specified in the user-defined dictionaries. We must make sure to ignore such declarations (perhaps alongside emitting a warning to the user) and only apply those that are correctly formed and exist.
+Aside from additional parsing required for the settings file (which inherently offers more locations for parsing to fail), we need to be careful about badly formed/non-existent feature tags or axes specified in the user-defined dictionaries. We must make sure to ignore such declarations (perhaps alongside emitting a warning to the user) and only apply those that are correctly formed and exist.
### Compatibility
diff --git a/doc/specs/#2871 - Pane Navigation/#2871 - Pane Navigation.md b/doc/specs/#2871 - Pane Navigation/#2871 - Pane Navigation.md
index 64fcf5d782b..e4b5ec6a4f1 100644
--- a/doc/specs/#2871 - Pane Navigation/#2871 - Pane Navigation.md
+++ b/doc/specs/#2871 - Pane Navigation/#2871 - Pane Navigation.md
@@ -241,7 +241,7 @@ So `focusPane(target=1, direction=up)` will attempt to focus the pane above pane
> 👉 **NOTE**: At this point, the author considered "Do we even want a separate
> action to engage the tab switcher with panes expanded?" Perhaps panes being
-> visible in the tab switcher is just part fo the tab switcher's behavior. Maybe
+> visible in the tab switcher is just part of the tab switcher's behavior. Maybe
> there shouldn't be a separate "open the tab switcher with the panes expanded
> to the pane I'm currently on, and the panes listed in MRU order" action.
diff --git a/doc/specs/#492 - Default Terminal/spec.md b/doc/specs/#492 - Default Terminal/spec.md
new file mode 100644
index 00000000000..e54b4d71b9d
--- /dev/null
+++ b/doc/specs/#492 - Default Terminal/spec.md
@@ -0,0 +1,270 @@
+---
+author: Michael Niksa @miniksa
+created on: 2020-08-14
+last updated: 2022-01-13
+issue id: #492
+---
+
+# Default Terminal Choice in Windows OS
+
+## Abstract
+
+Since the beginning, Windows has offered a single choice in default terminal hosting behavior. Specifically, the default terminal is defined as the one that the operating system will start on your behalf when a command-line application is started without a terminal attached. This specification intends to detail how we will offer customers the ultimate in choice among first and third party replacements for their default terminal experience.
+
+## Inspiration
+
+We've had a lot of success in the past several years on our terminal team journey. We updated the old console host user interface with long-desired features. We updated the console environment to bring Windows closer to Linux and Mac by implementing the client (receiving) end of Virtual Terminal sequences to unlock WSL, Docker, and other cross-platform command-line application compatibility. We then created the ConPTY to expose the server end of the console environment to first and third party applications to enable the hosting of any of those command-line clients within their own user interfaces by implementing the server (sending) end of Virtual Terminal sequences. And then we built Windows Terminal as our flagship implementation of the development environment on this model.
+
+Through all of this, the entrypoint for alternatives to the console host UX continued to be "Start your alternative terminal implementation first, then start the command-line application inside." For those familiar with Linux and Mac or for those using the broad ecosystem of alternative Windows Terminals like ConEmu, Cmder, Console2, and the like... that was natural. But Windows did it differently a long time ago allowing the starting of a command-line application directly from the shell or kernel without a terminal specified. On noticing the missing terminal, the system would just-in-time start and attach the one terminal it could count on as always present, `conhost.exe`.
+
+And so the inspiration of this is simple: We want to allow our customers to choose whichever terminal they want as the just-in-time terminal attached to an application without one present/specified on launch. This final move completes our journey to allow the ultimate in choice AND decouple the terminal experience from the operating system release schedule.
+
+## Solution Design
+
+There are three components to the proposed design:
+
+1. **Inbox console**: This is the `conhost.exe` that is resident inside every Windows installation.
+1. **Updated console**: This is the `openconsole.exe` that we ship with the Windows Terminal to provide a more up-to-date console server experience.
+1. **Terminal UX**: This is `WindowsTerminal.exe`, the new Terminal user interface that runs on VT sequences.
+
+And there are a few scenarios here to consider:
+
+1. Replacement console API server and replacement terminal UX.
+ 1. This is the Windows Terminal scenario today. `OpenConsole.exe` is packed in the package to be the console API server and ConPTY environment for `WindowsTerminal.exe`.
+1. Replacement console API server and legacy terminal UX.
+ 1. We don't explicitly distribute this today, but it's technically possible to just run `OpenConsole.exe` to accomplish this.
+1. Inbox console API server and replacement terminal UX.
+ 1. The WSL environment does this when doing Windows interop and I believe VS Code does this too when told to use the ConPTY environment. (And since VS Code does it, anything using node-pty also does it, covering some 3rd party terminals as well).
+1. Inbox console API server and inbox terminal UX.
+ 1. This is what we have today in `conhost.exe` running as the default application.
+
+The goal is to offer the ultimate in choice here where any of the components can be replaced as necessary for a 1st or 3rd party scenario.
+
+### Overview
+
+#### Inbox console
+
+The inbox console will be updated to support delegation of the incoming console client application connection to another console API server if one is registered and available.
+
+We leave the inbox console in-place and always available on the operating system for these reasons:
+
+1. A last chance fall-back should any of the delegation operations fail
+1. An ongoing host for applications that aren't going to need a window at all
+1. Continued support of our legacy `conhostv1.dll` environment, if chosen
+
+The general operation is as follows:
+
+- A command-line client application is started (from the start menu, run box, or any other `CreateProcess` or `ShellExecute` route) without an existing console server attached
+- The inbox console is launched from `C:\windows\system32\conhost.exe` as always by the initialization routines inside `kernelbase.dll`.
+- The inbox console accepts the incoming initial connection and looks for the `ShowWindow` information on the connection packet, as received from the kernel's process creation routines based on the parameters given to the `CreateProcess` call. (See [CREATE_NO_WINDOW](https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags) flag for details.)
+- If the session is about to create a window, check for registration of a delegated/updated console and hand-off to it if it exists.
+- Otherwise, start normally.
+
+This workflow affords us several benefits:
+
+- The only inbox component we have to change is `conhost.exe`, the one we already regularly update from open source on a regular basis. There is no change to the `kernelbase.dll` console initialization routines, `conclnt.lib` communication protocol, nor the `condrv.sys` driver.
+- We should be able to make this change quickly, relatively easily, and the code delta should be relatively small
+ - This makes it easy to squeeze in early in the development of the solution and get it into the Windows OS product as soon as possible for self-hosting, validation, and potentially shipping in the OS before the remainder of the solution has shaken out
+ - This also makes it potentially possible to backport this portion of the code change to popular in-market versions of Windows 10. For instance, WSL2 has just backported to 1903 and 1909. The less churn and risk, the easier it is to sell a backport.
+
+*Potential future:*
+- ~~If no updated console exists, potentially check for registration of a terminal UX that is willing to use the inbox ConPTY bits, start it, and transition to being a PTY instead.~~
+- **CUT FROM v1**: To simplify the story for end-users, we're offering this as a package deal in the first revision. Explaining the difference between consoles and terminals to end users is very difficult.
+
+The registration would operate as follows:
+- A registry key in `HKCU\Console\%%Startup` (format `REG_SZ`, name `DelegationConsole`) would specify ~~the path to ~~the replacement console that would be used to service the remainder of the connection process.
+ - Alternatively or additionally, this same `REG_SZ` could list a COM server ID that could be looked up in the classes root and invoked. **V1 NOTE:** This was what was done.
+ - Packaged applications and classic applications can easily register a COM server
+ - WinRT libraries should be able to be easily registered as the COM server as well (given WinRT is COM underneath)
+ - WinRT cannot be exposed outside of the package context itself, so the `conhost.exe` that is in the OS and is naturally outside the package cannot find it.
+ - **V1 NOTE:** The subkey `%%Startup` was chosen to separate these keys (this one and the `DelegationTerminal` one below) in case we needed to ACL them or protect them in some way. We want a per-user choice of which Terminal/Console are used, but we might need to take action to prevent these keys from being slammed at some point in the future. Why `%%`? The subkeys are traditionally used to resolve paths to client binaries that have their own console preferences set. The `%%` should never be resolvable as it won't lead to a valid path or expanded path variable.
+
+The delegation process would operate as follows:
+- A method contract is established between the existing inbox console and any updated console (an interface).
+ - `HRESULT ConsoleEstablishHandoff(HANDLE server, HANDLE driverInputEvent, const PortableConnectMessage* const msg, HANDLE signalPipe, HANDLE inboxProcess, HANDLE* process)`
+ - `HANDLE server`: This is the server side handle to the console driver, used with `DeviceIoControl` to receive/send messages with the client command-line application
+ - `HANDLE driverInputEvent`: The input event is created and assigned to the driver immediately on first connection, before any messages are read from the driver, to ensure that it can track a blocking state should first message be an input request that we do not yet have data to fill. As such, the inbox console will have created this and assigned it to the driver before pulling off the connection packet and determining that it wants to delegate. Therefore, we will transfer ownership of this event to the updated console.
+ - ~~`const PortableArguments* const args`: This contains the startup argument information that was passed in when the process was started including the original command line and the in/out handles.~~
+ - ~~The `ConsoleArguments` structure could technically change between versions, so we will make a version agnostic portable structure that just carries the communication from the old one to the new one.~~
+ - **CUT FROM V1**: The only arguments coming in from a default light-up are the server handle. Pretty much all the other arguments are related to the operation of the PTY. Since this feature is about "default application" launches where no arguments are specified, this was cut from the initial revision.
+ - `const PortableConnectMessage* const msg`:
+ - The `CONSOLE_API_MSG` structure contains both the actual packet data from the driver as well as some overhead/administration data related to the packet state, ordering, completion, errors, and buffers. It's a broad scope structure for every type of message we process and it can change over time as we improve the way the `conserver.lib` handles packets.
+ - This represents a version agnostic variant for ONLY the connect message that can pass along the initial connect information structure, the packet sequencing information, and other relevant payload only to that one message type. It will purposefully discard references to things like a specific set of API servicing routines because the point of handing off is to get updated routines, if necessary.
+ - **V1 NOTE:** This was named `CONSOLE_PORTABLE_ATTACH_MSG`
+ - `HANDLE signalPipe`: During authoring, it was identified that Ctrl+C and other similar signals need to make it back to the original `conhost.exe` application as the Operating System grants it special privilege over the originally attached client application. This privilege cannot be transferred to the delegated console. So this channel remains for the delegated one to send its signals back through the original one for commanding the underlying client. (This also implies the original `conhost.exe` inbox cannot close and must remain a part of the process tree for the life of the session to maintain this control.)
+ - `HANDLE inboxProcess`: Since we have to keep the inbox `conhost.exe` running for signal/ownership reasons, we also need to track its lifetime. If it disappears for whatever reason, we need to tear down the entire chain as part of our operation has been compromised.
+ - `HANDLE* process`: On the contrary to `inboxProcess`, we need to give our process handle back so it can also be tracked. After the inbox console delegates, it remains in a very limited capacity. If the delegation one disappears, the session will no longer function and needs to be torn down (and the client closed).
+ - *Return* `HRESULT`: This is one of the older style methods in the initialization. We moved them from mostly `NTSTATUS` to mostly `HRESULT` a while ago to take advantage of `wil`. This one will continue to follow the pattern and not move to exceptions. A return of `S_OK` will symbolize that the handoff worked and the inbox console can clean itself up and stop handling the session.
+- When the connection packet is parsed for visibility information (see `srvinit.cpp`), we will attempt to resolve the registered handoff and call it.
+ - ~~In the initial revision here, I have this as a `LoadLibrary`/`GetProcAddress` to the above exported contract method from the updated console. This maintains the server session in the same process space and avoids:~~
+ 1. ~~The issue of passing the server, event, and other handles into another process space. We're not entirely sure if the console driver will happily accept these things moving to a different process. It probably should, but unconfirmed.~~
+ 1. ~~Some command-line client applications rely on spelunking the process tree to figure out who is their servicing application. Maintaining the delegated/updated console inside the same process space maintains some level of continuity for these sorts of applications.~~
+ - **Alternative:** We may make this just be a COM server/client contract. ~~An in-proc COM server should operate in much the same fashion here (loading the DLL into the process and running particular method) while being significantly more formal and customizable (version revisions, moving to out-of-proc, not really needing to know the binary path because the catalog knows).~~
+ - **V1 NOTE:** We landed on an out-of-proc COM server/client here. This maintains the isolation of the newly running code from the old code. Since we're maintaining the original `conhost.exe` for signaling purposes, we're no longer worried about the spelunking the process tree and not having the relationship for clients to find.
+ - **Not considering:** ~~WinRT. `conhost.exe` has no WinRT. Adding WinRT to it would significantly increase the complexity of compilation in the inbox and out of box code base. It would also significantly increase the compilation time, binary size, library link list, etc... unless we use just the ABI to access it. But I don't see an advantage to that over just using classic COM at that point. This is only one handoff method and a rather simplistic one at that. Every benefit WinRT provides is outweighed by the extra effort that would be required over just a classic COM server in this case.~~
+- After delegation is complete, the inbox console will have to clean up any threads, handles, and state related to the session. We do a fairly good job with this normally, but some portions of the `conhost.exe` codebase are reliant on the process exiting for final cleanup. There may be a bit of extra effort to do some explicit cleanup here.
+ - **V1 NOTE:** The inbox one cleans up everything it can and sits in a state waiting for the child/delegated process handle to exit. It also maintains a thread listening for the signals to come through in case it needs to send a command to the client application using the privilege granted to it by the driver.
+
+#### Updated console
+
+The updated replacement console will have the same console API server capabilities as the inbox console, but will be a later, updated, or customized-to-the-scenario version of the API server generally revolving around improving ConPTY support for a Terminal application.
+
+On receiving the handoff from the method signature listed above, the updated console will:
+- Establish its own set of IO threading, device communication infrastructure, and API messaging routines while storing the handles given
+- ~~Re-parse the command line arguments, if necessary, and store them for guiding the remainder of launch~~
+- Dispatch the attach message as if it were received normally
+- Continue execution from there
+
+There will then either be a registration for a Terminal UX to take over the session by using ConPTY, ~~or the updated console will choose to launch its potentially updated version of the `conhost` UX~~.
+
+For registration, we repeat the dance above with another key:
+- A registry key in `HKCU\Console\%%Startup` (format `REG_SZ`, name `DelegationTerminal`).
+
+The delegation repeats the same dance as above as well:
+- A contract (interface) is established between the updated console and the terminal
+ - `HRESULT EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client)`
+ - `HANDLE in`: The handle to read client application output from the ConPTY and display on the Terminal
+ - `HANDLE out`: The handle to write user input from the Terminal to the ConPTY
+ - `HANDLE signal`: The signal handle for the ConPTY for out-of-band communication between PTY server and Terminal application
+ - ~~`COORD size`: The initial window size from the starting application, as it can be a preference in the connection structure. (A resize message may get sent back downward almost immediately from the Terminal as its dimensions could be different.)~~ **V1 NOTE:** This proved unnecessary as the resize operations sorted themselves out naturally.
+ - `HANDLE ref`: This is a "client reference handle" to the console driver and session. We hold onto a copy of this in the Terminal so the session will stay alive until we let go. (The other console hosts in the chain also hold one of these, as should the client.)
+ - `HANDLE server`: This is a process handle to the PTY we're attached to. We monitor this to know when the PTY is still alive from the Terminal side.
+ - `HANDLE client`: This is a process handle to the underlying client application. The terminal tracks this for exit handling.
+ - **Alternative:** This should likely just be a COM server/client contract as well. This would be consistent with the above and wouldn't require argument parsing or wink/nudge understanding of standard handle passing. It also conveys the same COM flexibility as described in the inbox console section. **V1 NOTE:** We used this alternative. We used COM, not a well-known exported function from the prototype.
+- The contract is called and on success, responsibility of the UX is given over to the Terminal. The console sits in PTY mode.
+ - On failure, the console launches interactive.
+
+#### Terminal UX
+
+The terminal will be its own complete presentation and input solution on top of a ConPTY connection, separating the concerns between API servicing and the user experience.
+
+Today the Terminal knows how to start and then launches a ConPTY under it. The Terminal will need to be updated to accept a pre-existing ConPTY connection on launch (or when the multi-process model arrives, as an inbound connection), and connect that to a new tab/pane instead of using the `winconpty.lib` libraries to make its own.
+
+For now, I'm considering only the fresh-start scenario.
+- The Terminal will have to detect the inbound connection through ~~its argument parsing (or through~~ a new entrypoint in the COM alternative ~~)~~ and store the PTY in/out/signal handles for that connection in the startup arguments information
+- When the control is instantiated on a new tab, that initial creation where normally the "default profile" is launched will instead have to place the PTY in/out/signal handles already received into the `ConPtyConnection` object and use that as if it was already created.
+- The Terminal can then let things run normally and the connection will come through and be hosted inside the session.
+
+There are several issues/concerns:
+- Which profile/settings get loaded? We don't really know anything about the client that is coming in already-established. That makes it difficult to know what user preferences to apply to the inbound tab. We could:
+ - Use only the defaults for the incoming connection. Do not apply any profile-specific settings.
+ - Use the profile information from the default profile to some degree. This could cause some weird scenarios/mismatches if that profile has a particular icon or a color scheme that makes it recognizable to the user.
+ - Create some sort of "inbound profile" profile that is used for incoming connections
+ - Add a heuristic that attempts to match the name/path of the connecting client binary to a profile that exists and use those settings, falling back if one is not found.
+ - **Proposal:** Do the first one immediately for bootstrapping, then investigate the others as a revision going forward.
+- The handles that are coming in are "raw" and "unpacked", not in the nice opaque `HPCON` structure that is usually provided to the `ConPtyConnection` object by the `winconpty.lib`.
+ - Add methods to `winconpty.lib` that allow for the packing of incoming raw handles into the `HPCON` structure so the rest of the lifetime can be treated the same
+ - Put the entrypoint for the COM server (or delegate the entrypoint for an argument) directly into this library so it can pack them up right away and hand of a ready-made `HPCON`.
+
+## UI/UX Design
+
+The user experience for this feature overall should be:
+
+1. The user launches a command-line client application through the Start Menu, Win+X menu, the Windows Explorer, the Run Dialog box (WinKey+R), or through another existing Windows application.
+1. Using the established settings, the console system transparently starts, delegates itself to the updated console, switches itself into ConPTY mode, and a copy of Windows Terminal launches with the first tab open to host the command-line client application.
+ - **NOTE:** I'm not precluding 3rd party registrations of either the delegation updated console nor the delegation terminal. It is our intention to allow either or both of these pieces to be replaced to the user's desires. The example is for brevity of our golden path and motivation for this scenario.
+1. The user is able to interact with the command-line client application as they would with the original console host.
+ - The user receives the additional benefit that short-running executions of a command-line application may not "blink in and disappear" as they do today when a user runs something like `ipconfig` from the run dialog. The Terminal's default states tend to leave the tab open and say that the client has exited. This would allow a Run Dialog `ipconfig` user an improved experience over the default console host state of disappearing quickly.
+1. If any portion of the delegation fails, we will progressively degrade back to a `conhost` style Win32+GDI UX and nothing will be different from before.
+
+The settings experience includes:
+- Configuration of the delegation operations:
+ - Locations:
+ - With the registry
+ - This is what's going to be available first and will remain available. We will progress to some or all of the below after.
+ - We will need to potentially add specifications to this to both the default profile (for new installations of Windows) or to upgrade/migration profiles (for users coming from previous editions of Windows) to enable the delegation process, especially if we put a copy of Windows Terminal directly into the box.
+ - **V1 NOTE:** we didn't add additional migration logic here as `HKCU\Console*` and subkeys were already in the migration logic, so adding another should just carry along.
+ - Inside Windows Terminal
+ - Inside the new Settings UI, we will likely need a page that configures the delegation keys in `HKCU\Console\%%Startup` ~~or a link out to the Windows Settings panel, should we manage to get the settings configurable there~~.
+ - Inside the console property sheet
+ - Same as for Terminal but with `comctl` controls over XAML +/- a link to the Windows Settings panel
+ - Inside the Settings panel for Windows (probably on the developer settings page)
+ - The ultimate location for this is likely a panel directly inside Windows. This is the hardest one to accomplish because of the timelines of the Windows product. We may not get this in an initial revision, but it should likely be our ultimate goal. **V1 NOTE:** We did it!
+ - Operation:
+ - Specify paths/server IDs - This is the initial revision
+ - Offer a list of registered servers or discovered manifests from the app catalog - This is the ideal scenario where we search the installed app catalog +/- the COM catalog and offer a list of apps that conform to the contract in a drop-down.
+ - The final process was to use [App Extensions](https://docs.microsoft.com/windows/uwp/launch-resume/how-to-create-an-extension) inside the Terminal APPX package to declare the COM GUIDs that were available for the `DelegationConsole` and `DelegationTerminal` fields respectively. A configuration class `DelegationConfig` was added to `propslib.lib` that enables the lookup of these from the application state catalog and presents a list of them to choose from. It also manages reading and writing the registry keys.
+ - **V1 NOTE:** Our configuration options currently allow pairings of replacement consoles and terminals to be adjusted in lock-step from the UI. That's not to say further combinations are not possible or even necessarily inhibited by the code. We just went for minimal confusion in our first round.
+
+- Configuration of the legacy console state:
+ - ~~Since we could end up in an experience where the default launch experience gets you directly into Windows Terminal, we believe that the Terminal will likely need an additional setting or settings in the new Settings UI that will allow the toggling of some of the `HKCU\Console` values to do things like set/remove the legacy console state.~~ **V1 NOTE:** Cut as low priority. Switch back to console and configure it that way or use the existing property sheet or tamper with registry keys.
+ - We have left the per-launch debugging and advanced access hole of calling something like `conhost.exe cmd.exe` which will use the inbox conhost to launch `cmd.exe` even if there is a default specified.
+
+Concerns:
+- State separation policy for Windows. I believe `HKCU\Console` is already specified as a part of the "user state" that should be mutable and carried forward on OS Swap, especially as we have been improving the OS swap experience.
+- Ability for installers/elevated scripts to stomp the Delegation keys
+ - This was a long time problem for default app registrations and was limited in our OS. Are we about to run down the same path?
+ - What is the alternative here? To use a protocol handler? To store this configuration state data with other protected state in a registry area that is mutable, but only ACL'd to the `SYSTEM` user like some other things in the Settings control panel?
+ - **V1 NOTE:** We set ourselves up for some future ACL thing with the subkey, but we otherwise haven't enforced anything at this time.
+
+## Capabilities
+
+### Accessibility
+
+Accessibility applications are the most likely to resort to a method of spelunking the process tree or window handles to attempt to find content to read out. Presuming they have hardcoded rules for console-type applications, these algorithms could be surprised by the substitution of another terminal environment.
+
+The major players here that I am considering are NVDA, JAWS, and Narrator. As far as I am aware, all of these applications attempt to drive their interactivity through UI Automation where possible. And we have worked with all of these applications in the past in improving their support for both `conhost.exe` and the Windows Terminal product. I have relatively high confidence that we will be able to work with them again to help update these assistive products to understand the new UI delegation, if necessary.
+
+### Security
+
+Let's hit the elephant in the room. "You plan on pulling a completely different binary inside the `conhost.exe` process and just... delegating all activity to it?" Yes.
+
+(**V1 NOTE:** Well, it's out of proc now. But it is at the same privilege level as the original one thanks to the mechanics of COM.)
+
+As far as I'm concerned, the `conhost.exe` that is started to host the command-line client application is running at the same integrity level as the client binary that is partially started and waiting for its server to be ready. This is the long-standing existing protection that we have from the Windows operating system. Anything running in the same integrity level is already expected to be able to tamper with anything else at the same integrity level. The delegated binary that we would be loading into our process space will also be at the same integrity level. Nothing really stops a malicious actor from launching that binary in any other way in the same integrity level as a part of the command-line client application's startup.
+
+The mitigation here, if necessary, would be to use `WinVerifyTrust` to validate the certification path of the `OpenConsole.exe` binary to ensure that only one that is signed by Microsoft can be the substitute server host for the application. This doesn't stop third parties from redistributing our `OpenConsole.exe` off of GitHub if necessary with their products, but it would stop someone from introducing any random binary that met the signature interface of the delegation methods into `conhost.exe`. The only value I see this providing is stopping someone from being "tricked" into delegating their `conhost.exe` to another binary through the configuration methods we provide. It doesn't really stop someone (or an attacker) from taking ownership of the `conhost.exe` in System32 and replacing it directly. So this point might be moot. (It is expected that replacement of the System32 one is already protected, to some degree, by being owned by the SYSTEM account and requiring some measure of authority to replace.)
+
+### Reliability
+
+The change on its own may honestly improve reliability of the hosting system. The existing just-in-time startup of the console host application only had a single chance at initializing a user experience before it would give up and return that the command-line application could not be started.
+
+However, there are now several phases in the startup process that will have the opportunity to make multiple attempts at multiple versions or applications to find a suitable host for the starting application before giving up.
+
+One layer of this is where the `conhost.exe` baked into the operating system will be on the lookout for an `OpenConsole.exe` that will replace its server activities. The delegation binary loses a bit of reliability, theoretically, by the fact that loading another process during launch could have versioning/resolution/path/dependency issues, but it simultaneously offers us the opportunity for improved reliability by being able to service that binary quickly outside the Windows OS release cycle. Fixes can arrive in days instead of months to years.
+
+Another layer of this is where either `conhost.exe` or the delegated `OpenConsole.exe` server will search for a terminal user experience host, like `WindowsTerminal.exe` or another registered first or third party host, and split the responsibility of hosting the session with that binary. Again, there's a theoretical reliability loss with the additional process launch/load, but there's much to be gained by reducing the scope of what each binary must accomplish. Removing the need to handle user interaction from `conhost.exe` or `OpenConsole.exe` and delegating those activities means there is less surface area running and less chance for a UX interaction to interfere with API call servicing and vice versa. And again, having the delegation to external components means that they can be fixed on a timeline of days instead of months or years as when baked into the operating system.
+
+### Compatibility
+
+One particular scenario that this could break is an application that makes use of spelunking the process tree when a command-line application starts to identify the hosting terminal application window by HWND to inject input, extract output, or otherwise hook and bind to hosting services. As the default application UI that will launch may not have the `conhost.exe` name (for spelunking via searching processes) and the HWND located may either be the ConPTY fake HWND or an HWND belonging to a completely different UI, these applications might not work.
+
+Two considerations here:
+
+1. At a minimum, we must offer an opt-out of the delegation to another terminal for the default application.
+1. We may also want to offer a process-name, policy, manifest, or other per client application opt-out mechanism.
+
+**V1 NOTE:** There is no per-client specific way of doing this. The toggle is per-user and can be adjusted in 3 different places.
+
+### Performance, Power, and Efficiency
+
+I expect to take some degree of performance, power, and efficiency hit by implementing this replacement default app scenario just by it's nature. We will be loading multiple processes, performing tests and branches during startup, and we will likely need to load COM/WinRT and packaging data that was not loaded prior to resolve the final state of default application load. I would expect this to accrue to some failures in the performance and power gates inside the Windows product. Additionally, the efficiency of running pretty much everything through the ConPTY is lower than just rendering it directly to `conhost.exe`'s embedded GDI-powered UI itself thanks to the multiple levels of translation and parsing that occur in this scenario.
+
+The mitigations to these losses are as follows:
+
+1. We will delay load any of the interface load and packaging data lookup libraries to only be pulled into process space should we determine that the application is non-interactive.
+ 1. That should save us some of the commit and power costs for the sorts of non-interactive scripts and applications that typically run early in OS startup (and leverage `conhost.exe` as their host environment).
+ 1. We will still likely get hit with the on-disk commit cost for the additional export libraries linked as well as additional code. That would be a by-design change.
+
+1. We plan to begin Profile Guided Optimization across our `OpenConsole.exe` and `WindowsTerminal.exe` binaries. This should allow us to optimize the startup paths for this scenario and bias the `OpenConsole.exe` binary that we redistribute to focus its efforts and efficiency on the ConPTY role specifically, ignoring all of the interactive Win32/GDI portions that aren't typically used.
+ 1. We may need to add a PGO scenario inside Windows to tune the optimization of `conhost.exe` especially if we're going to go full on Windows Terminal in the box default application. The existing PGO that occurs in the optimization branches is running on several `conhost.exe` interactive scenarios, none of which will be relevant here. We would probably want to update it to focus on the default app delegation routine AND on the non-interactive scenario for hosted applications (where delegation will not occur but Win32/GDI will still not be involved).
+
+## Potential Issues
+
+### Passing Handles with COM
+COM doesn't inherently expose a way for us to pass handles directly between processes with the existing contracts. We know this is possible because Windows does it all the time, but it doesn't appear to be public. We believe the mission forward is to expose this functionality to the public as if it's good enough for us internally and it is a requirement to build complex functionality like this... then it should be good enough for the public.
+
+**V1 NOTE:** We gained approval to open this up and documented it. [`system_handle` attribute](https://docs.microsoft.com/windows/win32/midl/system-handle). It didn't require any code changes because the public IDL compiler already recognized the existence of this attribute and did the correct thing. It just wasn't documented for use.
+
+## Future considerations
+
+* We additionally would like to leave the door open to distributing updated `OpenConsole.exe`s in their own app package as a dependency that others could rely on.
+ * This was one of the original management requests when we were opening the source of the console product as well as the Terminal back in spring of 2019. For the sake of ongoing servicing and maintainability, it was requested that we reach a point where our dependencies could be serviced potentially independently of the product as a whole static unit. We didn't achieve that goal initially, but this design would enable us to do something like this.
+ * One negative to this scenario is that dependency resolution and the installation of dependent packages through APPX is currently lacking in several ways. It's difficult/impossible to do in environments where the store or the internet is unavailable. And it's a problem often enough that the Windows Terminal package embeds the VC runtimes inside itself instead of relying on the dependency resolution of the app platform.
+
+## Resources
+
+- [Windows Terminal Process Model 2.0 spec](https://github.com/microsoft/terminal/pull/7240)
+- [Windows Terminal 2.0 Process Model Improvements](https://github.com/microsoft/terminal/issues/5000)
+- [Console allocation policy specifications](https://github.com/microsoft/terminal/pull/7337)
+- [Fine-grained console allocation policy feature](https://github.com/microsoft/terminal/issues/7335)
diff --git a/doc/specs/#5000 - Process Model 2.0/#1032 - Elevation Quality of Life Improvements.md b/doc/specs/#5000 - Process Model 2.0/#1032 - Elevation Quality of Life Improvements.md
index 1757352e9ca..a1137a77ac9 100644
--- a/doc/specs/#5000 - Process Model 2.0/#1032 - Elevation Quality of Life Improvements.md
+++ b/doc/specs/#5000 - Process Model 2.0/#1032 - Elevation Quality of Life Improvements.md
@@ -552,7 +552,7 @@ following behaviors:
* `false`: If the current window is elevated, try to create a new unelevated
window to host this connection.
-We could always re-introduce this setting, to supercede `elevate`.
+We could always re-introduce this setting, to supersede `elevate`.
### Change profile appearance for elevated windows
diff --git a/doc/specs/#5000 - Process Model 2.0/#5000 - Process Model 2.0.md b/doc/specs/#5000 - Process Model 2.0/#5000 - Process Model 2.0.md
index c1a3dee38d9..e32af6b72ea 100644
--- a/doc/specs/#5000 - Process Model 2.0/#5000 - Process Model 2.0.md
+++ b/doc/specs/#5000 - Process Model 2.0/#5000 - Process Model 2.0.md
@@ -1123,7 +1123,7 @@ elevated windows, when they trust the extension. We could have an additional set
of settings the user could use to enable certain extensions in elevated windows.
However, this setting cannot live in the normal `settings.json` or even
`state.json` (see [#7972], since those files are writable by any medium-IL
-process. Instead, this setting would ned to live in a separate file that's
+process. Instead, this setting would need to live in a separate file that's
protected to only be writable by elevated processes. This would ensure that an
attacker could not just add their extension to the list of white-listed
extensions. When the settings UI wants to modify that setting, it'll need to
diff --git a/doc/specs/#6899 - Action IDs/#6899 - Action IDs.md b/doc/specs/#6899 - Action IDs/#6899 - Action IDs.md
index c3d2871cb36..50faf9d1efb 100644
--- a/doc/specs/#6899 - Action IDs/#6899 - Action IDs.md
+++ b/doc/specs/#6899 - Action IDs/#6899 - Action IDs.md
@@ -26,7 +26,7 @@ This spec was largely inspired by the following diagram from @DHowett:
![figure 1](data-mockup.png)
The goal is to introduce an `id` parameter by which actions could be uniquely
-refered to. If we'd ever like to use an action outside the list of `actions`, we
+referred to. If we'd ever like to use an action outside the list of `actions`, we
can simply refer to the action's ID, allowing the user to only define the action
_once_.
diff --git a/doc/specs/#885 - Terminal Settings Model/#885 - Terminal Settings Model.md b/doc/specs/#885 - Terminal Settings Model/#885 - Terminal Settings Model.md
index c7dbefeab0b..ad361218403 100644
--- a/doc/specs/#885 - Terminal Settings Model/#885 - Terminal Settings Model.md
+++ b/doc/specs/#885 - Terminal Settings Model/#885 - Terminal Settings Model.md
@@ -230,7 +230,7 @@ def cloneGraph(oldSource, newSource, visited):
for old in oldSource.adj:
# Below check is for backtracking, so new
- # nodes don't get initialized everytime
+ # nodes don't get initialized every time
if clone is None or(clone is not None and clone.key != old.key):
clone = Node(old.key, [])
newSource.adj.append(clone)
diff --git a/doc/specs/TerminalSettings-spec.md b/doc/specs/TerminalSettings-spec.md
index 1bf098274a8..16d3cfbd938 100644
--- a/doc/specs/TerminalSettings-spec.md
+++ b/doc/specs/TerminalSettings-spec.md
@@ -58,7 +58,7 @@ VS needs to be able to persist settings just as a simple set of global settings.
When the application needs to retrieve these settings, they need to use them as a tripartite structure: frontend-component-terminal settings.
Each frontend will have its own set of settings.
-Each component implementation will also ned to have some settings that control it.
+Each component implementation will also need to have some settings that control it.
The terminal also will have some settings specific to the terminal.
### Globals and Profiles
diff --git a/doc/specs/drafts/#1256 - Tab tearoff.md b/doc/specs/drafts/#1256 - Tab tearoff.md
index d57a695067c..fa1b2e9a0d5 100644
--- a/doc/specs/drafts/#1256 - Tab tearoff.md
+++ b/doc/specs/drafts/#1256 - Tab tearoff.md
@@ -124,7 +124,7 @@ There's a few areas to study here.
#### Communicating the launch
For the parameters passing, I see a few options:
-1. `conhost.exe` can look up the package registration for `wt.exe` and call an entrypoint with arguments. This could be adapted to instead look up which package is registered as the default one instead of `wt.exe` for third party hosts. We would have to build provisions into the OS to select this, or use some sort of publically documented registry key mechanism. Somewhat gross.
+1. `conhost.exe` can look up the package registration for `wt.exe` and call an entrypoint with arguments. This could be adapted to instead look up which package is registered as the default one instead of `wt.exe` for third party hosts. We would have to build provisions into the OS to select this, or use some sort of publicly documented registry key mechanism. Somewhat gross.
1. `conhost.exe` can call the execution alias with parameters. WSL distro launchers use this.
1. We can define a protocol handler for these sorts of connections and let `wt.exe` register for it. Protocol handlers are already well supported and understood both by classic applications and by packaged/modern applications on Windows. They must have provisions to communicate at least some semblance of argument data as well. This is the route I'd probably prefer. `ms-term://incoming/` or something like that. The receiving `wt.exe` can contact the manager process (or set one up if it is the first) and negotiate receiving the session that was specified into a new tab.
diff --git a/doc/specs/drafts/#997 Non-Terminal-Panes.md b/doc/specs/drafts/#997 Non-Terminal-Panes.md
index 512165580bd..6fb539cf33c 100644
--- a/doc/specs/drafts/#997 Non-Terminal-Panes.md
+++ b/doc/specs/drafts/#997 Non-Terminal-Panes.md
@@ -77,7 +77,7 @@ is a bigger discussion than the feature at hand, however.
### Performance, Power, and Efficiency
decide to host a WebView in a pane, then it surely could impact these measures.
-I don't believe this will have a noticable impact _on its own_. Should the user
+I don't believe this will have a noticeable impact _on its own_. Should the user
However, I leave that discussion to the implementation of the actual alternative
pane content itself.
diff --git a/samples/ConPTY/MiniTerm/MiniTerm/PseudoConsole.cs b/samples/ConPTY/MiniTerm/MiniTerm/PseudoConsole.cs
index 84d3d3d44bf..50cb6064b64 100644
--- a/samples/ConPTY/MiniTerm/MiniTerm/PseudoConsole.cs
+++ b/samples/ConPTY/MiniTerm/MiniTerm/PseudoConsole.cs
@@ -26,7 +26,7 @@ internal static PseudoConsole Create(SafeFileHandle inputReadSide, SafeFileHandl
0, out IntPtr hPC);
if(createResult != 0)
{
- throw new InvalidOperationException("Could not create psuedo console. Error Code " + createResult);
+ throw new InvalidOperationException("Could not create pseudo console. Error Code " + createResult);
}
return new PseudoConsole(hPC);
}
diff --git a/samples/ReadConsoleInputStream/ReadConsoleInputStream.cs b/samples/ReadConsoleInputStream/ReadConsoleInputStream.cs
index 2b0c8088a21..cc3c9158a1e 100644
--- a/samples/ReadConsoleInputStream/ReadConsoleInputStream.cs
+++ b/samples/ReadConsoleInputStream/ReadConsoleInputStream.cs
@@ -136,7 +136,7 @@ public override int Read(byte[] buffer, int offset, int count)
if (record.EventType != Kernel32.EVENT_TYPE.FOCUS_EVENT)
{
// I assume success adding records - this is not so critical
- // if it is critical to you, loop on this with a miniscule delay
+ // if it is critical to you, loop on this with a minuscule delay
_nonKeyEvents.TryAdd(record);
}
}
@@ -195,4 +195,4 @@ private void ValidateRead(byte[] buffer, int offset, int count)
if (!CanRead) throw new NotSupportedException("Get read not supported.");
}
}
-}
\ No newline at end of file
+}
diff --git a/scratch/ScratchIslandApp/Package/Package.wapproj b/scratch/ScratchIslandApp/Package/Package.wapproj
index 8f526698b1c..4de7a05a3cf 100644
--- a/scratch/ScratchIslandApp/Package/Package.wapproj
+++ b/scratch/ScratchIslandApp/Package/Package.wapproj
@@ -140,12 +140,12 @@
-
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
diff --git a/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj b/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj
index 04b9b082496..5d84890f014 100644
--- a/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj
+++ b/scratch/ScratchIslandApp/SampleApp/SampleAppLib.vcxproj
@@ -147,13 +147,13 @@
-
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
diff --git a/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj b/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj
index 59d500ccc6e..91592d6f771 100644
--- a/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj
+++ b/scratch/ScratchIslandApp/SampleApp/dll/SampleApp.vcxproj
@@ -80,13 +80,13 @@
-
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
diff --git a/scratch/ScratchIslandApp/SampleApp/packages.config b/scratch/ScratchIslandApp/SampleApp/packages.config
index ec5cd9a0fbd..f167ce9570a 100644
--- a/scratch/ScratchIslandApp/SampleApp/packages.config
+++ b/scratch/ScratchIslandApp/SampleApp/packages.config
@@ -1,6 +1,6 @@
-
+
diff --git a/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj b/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj
index 18a5a05fe33..f83b237149c 100644
--- a/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj
+++ b/scratch/ScratchIslandApp/WindowExe/WindowExe.vcxproj
@@ -137,14 +137,14 @@
-
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
diff --git a/scratch/ScratchIslandApp/WindowExe/packages.config b/scratch/ScratchIslandApp/WindowExe/packages.config
index 319e836803c..cbcb02cb6dc 100644
--- a/scratch/ScratchIslandApp/WindowExe/packages.config
+++ b/scratch/ScratchIslandApp/WindowExe/packages.config
@@ -2,6 +2,6 @@
-
+
diff --git a/src/buffer/out/TextAttribute.cpp b/src/buffer/out/TextAttribute.cpp
index e626db89f3b..35046da07e8 100644
--- a/src/buffer/out/TextAttribute.cpp
+++ b/src/buffer/out/TextAttribute.cpp
@@ -91,7 +91,7 @@ TextAttribute TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(const Te
const auto bg{ attribute.GetBackground() };
auto copy{ attribute };
if (fg.IsIndex16() &&
- attribute.IsBold() == WI_IsFlagSet(s_ansiDefaultForeground, FOREGROUND_INTENSITY) &&
+ attribute.IsIntense() == WI_IsFlagSet(s_ansiDefaultForeground, FOREGROUND_INTENSITY) &&
fg.GetIndex() == (s_ansiDefaultForeground & ~FOREGROUND_INTENSITY))
{
// We don't want to turn 1;37m into 39m (or even 1;39m), as this was meant to mimic a legacy color.
@@ -115,7 +115,7 @@ WORD TextAttribute::GetLegacyAttributes() const noexcept
const BYTE fgIndex = _foreground.GetLegacyIndex(s_legacyDefaultForeground);
const BYTE bgIndex = _background.GetLegacyIndex(s_legacyDefaultBackground);
const WORD metaAttrs = _wAttrLegacy & META_ATTRS;
- const bool brighten = IsBold() && _foreground.CanBeBrightened();
+ const bool brighten = IsIntense() && _foreground.CanBeBrightened();
return fgIndex | (bgIndex << 4) | metaAttrs | (brighten ? FOREGROUND_INTENSITY : 0);
}
@@ -255,9 +255,9 @@ void TextAttribute::SetRightVerticalDisplayed(const bool isDisplayed) noexcept
WI_UpdateFlag(_wAttrLegacy, COMMON_LVB_GRID_RVERTICAL, isDisplayed);
}
-bool TextAttribute::IsBold() const noexcept
+bool TextAttribute::IsIntense() const noexcept
{
- return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Bold);
+ return WI_IsFlagSet(_extendedAttrs, ExtendedAttributes::Intense);
}
bool TextAttribute::IsFaint() const noexcept
@@ -305,9 +305,9 @@ bool TextAttribute::IsReverseVideo() const noexcept
return WI_IsFlagSet(_wAttrLegacy, COMMON_LVB_REVERSE_VIDEO);
}
-void TextAttribute::SetBold(bool isBold) noexcept
+void TextAttribute::SetIntense(bool isIntense) noexcept
{
- WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Bold, isBold);
+ WI_UpdateFlag(_extendedAttrs, ExtendedAttributes::Intense, isIntense);
}
void TextAttribute::SetFaint(bool isFaint) noexcept
diff --git a/src/buffer/out/TextAttribute.hpp b/src/buffer/out/TextAttribute.hpp
index 70b15073642..bc8e42dae47 100644
--- a/src/buffer/out/TextAttribute.hpp
+++ b/src/buffer/out/TextAttribute.hpp
@@ -84,7 +84,7 @@ class TextAttribute final
friend constexpr bool operator!=(const WORD& legacyAttr, const TextAttribute& attr) noexcept;
bool IsLegacy() const noexcept;
- bool IsBold() const noexcept;
+ bool IsIntense() const noexcept;
bool IsFaint() const noexcept;
bool IsItalic() const noexcept;
bool IsBlinking() const noexcept;
@@ -95,7 +95,7 @@ class TextAttribute final
bool IsOverlined() const noexcept;
bool IsReverseVideo() const noexcept;
- void SetBold(bool isBold) noexcept;
+ void SetIntense(bool isIntense) noexcept;
void SetFaint(bool isFaint) noexcept;
void SetItalic(bool isItalic) noexcept;
void SetBlinking(bool isBlinking) noexcept;
@@ -214,10 +214,10 @@ namespace WEX
static WEX::Common::NoThrowString ToString(const TextAttribute& attr)
{
return WEX::Common::NoThrowString().Format(
- L"{FG:%s,BG:%s,bold:%d,wLegacy:(0x%04x),ext:(0x%02x)}",
+ L"{FG:%s,BG:%s,intense:%d,wLegacy:(0x%04x),ext:(0x%02x)}",
VerifyOutputTraits::ToString(attr._foreground).GetBuffer(),
VerifyOutputTraits::ToString(attr._background).GetBuffer(),
- attr.IsBold(),
+ attr.IsIntense(),
attr._wAttrLegacy,
static_cast(attr._extendedAttrs));
}
diff --git a/src/buffer/out/TextColor.cpp b/src/buffer/out/TextColor.cpp
index e20195ceaac..a1913189249 100644
--- a/src/buffer/out/TextColor.cpp
+++ b/src/buffer/out/TextColor.cpp
@@ -133,8 +133,8 @@ void TextColor::SetDefault() noexcept
// - If brighten is true, and we've got a 16 color index in the "dark"
// portion of the color table (indices [0,7]), then we'll look up the
// bright version of this color (from indices [8,15]). This should be
-// true for TextAttributes that are "Bold" and we're treating bold as
-// bright (which is the default behavior of most terminals.)
+// true for TextAttributes that are "intense" and we're treating intense
+// as bright (which is the default behavior of most terminals.)
// * If we're a default color, we'll return the default color provided.
// Arguments:
// - colorTable: The table of colors we should use to look up the value of
diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp
index 36266710a86..a7df90e8c76 100644
--- a/src/buffer/out/textBuffer.cpp
+++ b/src/buffer/out/textBuffer.cpp
@@ -1751,7 +1751,7 @@ const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
if (copyTextColor)
{
- // cant see CR/LF so just use black FG & BK
+ // can't see CR/LF so just use black FG & BK
COLORREF const Blackness = RGB(0x00, 0x00, 0x00);
selectionFgAttr.push_back(Blackness);
selectionFgAttr.push_back(Blackness);
@@ -2034,20 +2034,8 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
const auto writeAccumulatedChars = [&](bool includeCurrent) {
if (col >= startOffset)
{
- const auto unescapedText = ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent));
- for (const auto c : unescapedText)
- {
- switch (c)
- {
- case '\\':
- case '{':
- case '}':
- contentBuilder << "\\" << c;
- break;
- default:
- contentBuilder << c;
- }
- }
+ const auto text = std::wstring_view{ rows.text.at(row) }.substr(startOffset, col - startOffset + includeCurrent);
+ _AppendRTFText(contentBuilder, text);
startOffset = col;
}
@@ -2146,6 +2134,31 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
}
}
+void TextBuffer::_AppendRTFText(std::ostringstream& contentBuilder, const std::wstring_view& text)
+{
+ for (const auto codeUnit : text)
+ {
+ if (codeUnit <= 127)
+ {
+ switch (codeUnit)
+ {
+ case L'\\':
+ case L'{':
+ case L'}':
+ contentBuilder << "\\" << gsl::narrow(codeUnit);
+ break;
+ default:
+ contentBuilder << gsl::narrow(codeUnit);
+ }
+ }
+ else
+ {
+ // Windows uses unsigned wchar_t - RTF uses signed ones.
+ contentBuilder << "\\u" << std::to_string(til::bit_cast(codeUnit)) << "?";
+ }
+ }
+}
+
// Function Description:
// - Reflow the contents from the old buffer into the new buffer. The new buffer
// can have different dimensions than the old buffer. If it does, then this
diff --git a/src/buffer/out/textBuffer.hpp b/src/buffer/out/textBuffer.hpp
index a2b34ed5b88..fe87ee8822d 100644
--- a/src/buffer/out/textBuffer.hpp
+++ b/src/buffer/out/textBuffer.hpp
@@ -247,6 +247,8 @@ class TextBuffer final
void _PruneHyperlinks();
+ static void _AppendRTFText(std::ostringstream& contentBuilder, const std::wstring_view& text);
+
std::unordered_map _idsAndPatterns;
size_t _currentPatternId;
diff --git a/src/buffer/out/ut_textbuffer/TextAttributeTests.cpp b/src/buffer/out/ut_textbuffer/TextAttributeTests.cpp
index ae39257a9f1..b334b214c02 100644
--- a/src/buffer/out/ut_textbuffer/TextAttributeTests.cpp
+++ b/src/buffer/out/ut_textbuffer/TextAttributeTests.cpp
@@ -24,7 +24,7 @@ class TextAttributeTests
TEST_METHOD(TestTextAttributeColorGetters);
TEST_METHOD(TestReverseDefaultColors);
TEST_METHOD(TestRoundtripDefaultColors);
- TEST_METHOD(TestBoldAsBright);
+ TEST_METHOD(TestIntenseAsBright);
RenderSettings _renderSettings;
const COLORREF _defaultFg = RGB(1, 2, 3);
@@ -257,7 +257,7 @@ void TextAttributeTests::TestRoundtripDefaultColors()
TextAttribute::SetLegacyDefaultAttributes(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}
-void TextAttributeTests::TestBoldAsBright()
+void TextAttributeTests::TestIntenseAsBright()
{
const auto& colorTable = _renderSettings.GetColorTable();
const COLORREF darkBlack = til::at(colorTable, 0);
@@ -267,8 +267,8 @@ void TextAttributeTests::TestBoldAsBright()
TextAttribute attr{};
// verify that calculated foreground/background are the same as the direct
- // values when not bold
- VERIFY_IS_FALSE(attr.IsBold());
+ // values when not intense
+ VERIFY_IS_FALSE(attr.IsIntense());
VERIFY_ARE_EQUAL(_defaultFg, attr.GetForeground().GetColor(colorTable, _defaultFgIndex));
VERIFY_ARE_EQUAL(_defaultBg, attr.GetBackground().GetColor(colorTable, _defaultBgIndex));
@@ -277,46 +277,46 @@ void TextAttributeTests::TestBoldAsBright()
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, false);
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), _renderSettings.GetAttributeColors(attr));
- // with bold set, calculated foreground/background values shouldn't change for the default colors.
- attr.SetBold(true);
- VERIFY_IS_TRUE(attr.IsBold());
+ // with intense set, calculated foreground/background values shouldn't change for the default colors.
+ attr.SetIntense(true);
+ VERIFY_IS_TRUE(attr.IsIntense());
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, true);
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), _renderSettings.GetAttributeColors(attr));
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, false);
VERIFY_ARE_EQUAL(std::make_pair(_defaultFg, _defaultBg), _renderSettings.GetAttributeColors(attr));
attr.SetIndexedForeground(TextColor::DARK_BLACK);
- VERIFY_IS_TRUE(attr.IsBold());
+ VERIFY_IS_TRUE(attr.IsIntense());
- Log::Comment(L"Foreground should be bright black when bold is bright is enabled");
+ Log::Comment(L"Foreground should be bright black when intense is bright is enabled");
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, true);
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, _defaultBg), _renderSettings.GetAttributeColors(attr));
- Log::Comment(L"Foreground should be dark black when bold is bright is disabled");
+ Log::Comment(L"Foreground should be dark black when intense is bright is disabled");
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, false);
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, _defaultBg), _renderSettings.GetAttributeColors(attr));
attr.SetIndexedBackground(TextColor::DARK_GREEN);
- VERIFY_IS_TRUE(attr.IsBold());
+ VERIFY_IS_TRUE(attr.IsIntense());
- Log::Comment(L"background should be unaffected by 'bold is bright'");
+ Log::Comment(L"background should be unaffected by 'intense is bright'");
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, true);
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), _renderSettings.GetAttributeColors(attr));
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, false);
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), _renderSettings.GetAttributeColors(attr));
- attr.SetBold(false);
- VERIFY_IS_FALSE(attr.IsBold());
- Log::Comment(L"when not bold, 'bold is bright' changes nothing");
+ attr.SetIntense(false);
+ VERIFY_IS_FALSE(attr.IsIntense());
+ Log::Comment(L"when not intense, 'intense is bright' changes nothing");
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, true);
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), _renderSettings.GetAttributeColors(attr));
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, false);
VERIFY_ARE_EQUAL(std::make_pair(darkBlack, darkGreen), _renderSettings.GetAttributeColors(attr));
- Log::Comment(L"When set to a bright color, and bold, 'bold is bright' changes nothing");
- attr.SetBold(true);
+ Log::Comment(L"When set to a bright color, and intense, 'intense is bright' changes nothing");
+ attr.SetIntense(true);
attr.SetIndexedForeground(TextColor::BRIGHT_BLACK);
- VERIFY_IS_TRUE(attr.IsBold());
+ VERIFY_IS_TRUE(attr.IsIntense());
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, true);
VERIFY_ARE_EQUAL(std::make_pair(brightBlack, darkGreen), _renderSettings.GetAttributeColors(attr));
_renderSettings.SetRenderMode(RenderSettings::Mode::IntenseIsBright, false);
diff --git a/src/buffer/out/ut_textbuffer/sources b/src/buffer/out/ut_textbuffer/sources
index 6e025707077..570467fce63 100644
--- a/src/buffer/out/ut_textbuffer/sources
+++ b/src/buffer/out/ut_textbuffer/sources
@@ -21,6 +21,7 @@ SOURCES = \
TARGETLIBS = \
$(CONSOLE_OBJ_PATH)\buffer\out\lib\$(O)\ConBufferOut.lib \
+ $(CONSOLE_OBJ_PATH)\renderer\base\lib\$(O)\ConRenderBase.lib \
$(CONSOLE_OBJ_PATH)\types\lib\$(O)\ConTypes.lib \
$(TARGETLIBS) \
diff --git a/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj b/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj
index 48d8caffdf9..9aaffac83ee 100644
--- a/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj
+++ b/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj
@@ -11,7 +11,7 @@
-->
falsefalse
- wtd
+ wtdwt
@@ -38,7 +38,7 @@
Designer
-
+ Designer
@@ -52,7 +52,7 @@
-
+ -Dev
@@ -138,36 +138,34 @@
-
-
-
+
+
+
-
-
+
+
+
-
-
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
diff --git a/src/cascadia/CascadiaPackage/Package-Dev.appxmanifest b/src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
index 20c75fd5bba..0627906f7c0 100644
--- a/src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
+++ b/src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
@@ -20,7 +20,7 @@
Version="0.0.1.0" />
- Windows Terminal Dev
+ ms-resource:AppStoreNameDevA Lone DeveloperImages\StoreLogo.png
@@ -30,7 +30,7 @@
-
+
@@ -87,7 +87,7 @@
diff --git a/src/cascadia/CascadiaPackage/Package-Pre.appxmanifest b/src/cascadia/CascadiaPackage/Package-Pre.appxmanifest
index 3c0dc42e2be..a55af61e2a0 100644
--- a/src/cascadia/CascadiaPackage/Package-Pre.appxmanifest
+++ b/src/cascadia/CascadiaPackage/Package-Pre.appxmanifest
@@ -21,7 +21,7 @@
Version="0.5.0.0" />
- Windows Terminal Preview
+ ms-resource:AppStoreNamePreMicrosoft CorporationImages\StoreLogo.png
@@ -31,7 +31,95 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -88,7 +176,7 @@
diff --git a/src/cascadia/CascadiaPackage/Package.appxmanifest b/src/cascadia/CascadiaPackage/Package.appxmanifest
index 7b3ad6e4c12..cb99c9a07ea 100644
--- a/src/cascadia/CascadiaPackage/Package.appxmanifest
+++ b/src/cascadia/CascadiaPackage/Package.appxmanifest
@@ -21,7 +21,7 @@
Version="1.0.0.0" />
- Windows Terminal
+ ms-resource:AppStoreNameMicrosoft CorporationImages\StoreLogo.png
@@ -31,7 +31,95 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -88,7 +176,7 @@
diff --git a/src/cascadia/CascadiaPackage/Resources/Resources.resw b/src/cascadia/CascadiaPackage/Resources/Resources.resw
index 94a910fd0e9..07e77609519 100644
--- a/src/cascadia/CascadiaPackage/Resources/Resources.resw
+++ b/src/cascadia/CascadiaPackage/Resources/Resources.resw
@@ -117,22 +117,4 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- Windows Terminal
-
-
- Windows Terminal Dev
-
-
- Windows Terminal Preview
-
-
- Terminal
-
-
- Terminal Dev
-
-
- Terminal Preview
-
-
\ No newline at end of file
+
diff --git a/src/cascadia/CascadiaPackage/Resources/en-US/Resources.resw b/src/cascadia/CascadiaPackage/Resources/en-US/Resources.resw
index c2d6436947f..eced69ff25a 100644
--- a/src/cascadia/CascadiaPackage/Resources/en-US/Resources.resw
+++ b/src/cascadia/CascadiaPackage/Resources/en-US/Resources.resw
@@ -117,13 +117,52 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ Terminal
+ {Locked}
+
+
+ Terminal Dev
+ {Locked}
+
+
+ Terminal Preview
+ {Locked}
+
+
+ Windows Terminal
+ {Locked}
+
+
+ Windows Terminal Dev
+ {Locked}
+
+
+ Windows Terminal Preview
+ {Locked}
+
+
+ Terminal
+ {Locked}
+
+
+ Terminal Dev
+ {Locked}
+
+
+ Terminal Preview
+ {Locked}
+
The New Windows Terminal
+ {Locked}The Windows Terminal, but Unofficial
+ {Locked}Windows Terminal with a preview of upcoming features
+ {Locked}
-
\ No newline at end of file
+
diff --git a/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj b/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj
index f383f371001..2ad3e5508e3 100644
--- a/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj
+++ b/src/cascadia/LocalTests_SettingsModel/SettingsModel.LocalTests.vcxproj
@@ -81,8 +81,8 @@
If you don't have this, then you'll see an error like
"(init.obj) : error LNK2005: DllMain already defined in MSVCRTD.lib(dll_dllmain_stub.obj)"
-->
- /INCLUDE:_DllMain@12
- /INCLUDE:DllMain
+ %(AdditionalOptions) /INCLUDE:_DllMain@12
+ %(AdditionalOptions) /INCLUDE:DllMain
@@ -99,10 +99,10 @@
x86$(Platform)
- <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\runtimes\win10-$(Native-Platform)\native\"
+ <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\runtimes\win10-$(Native-Platform)\native\"
-
+
diff --git a/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp b/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp
index 100634874c8..ad2463bbb70 100644
--- a/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp
+++ b/src/cascadia/LocalTests_SettingsModel/TerminalSettingsTests.cpp
@@ -38,6 +38,7 @@ namespace SettingsModelLocalTests
TEST_METHOD(TryCreateWinRTType);
TEST_METHOD(TestTerminalArgsForBinding);
TEST_METHOD(CommandLineToArgvW);
+ TEST_METHOD(NormalizeCommandLine);
TEST_METHOD(GetProfileForArgsWithCommandline);
TEST_METHOD(MakeSettingsForProfile);
TEST_METHOD(MakeSettingsForDefaultProfileThatDoesntExist);
@@ -84,7 +85,8 @@ namespace SettingsModelLocalTests
for (int i = 0; i < expectedArgc; ++i)
{
const bool useQuotes = static_cast(rng(2));
- const auto count = static_cast(rng(64));
+ // We need to ensure there is at least one character
+ const auto count = static_cast(rng(64) + 1);
const auto ch = static_cast(rng('z' - 'a' + 1) + 'a');
if (i != 0)
@@ -106,6 +108,7 @@ namespace SettingsModelLocalTests
input.push_back(L'"');
}
}
+ Log::Comment(NoThrowString().Format(input.c_str()));
int argc;
wil::unique_hlocal_ptr argv{ ::CommandLineToArgvW(input.c_str(), &argc) };
@@ -120,6 +123,67 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(0, memcmp(beg, expectedArgv.data(), expectedArgv.size()));
}
+ // This unit test covers GH#12345.
+ // * paths with more than 1 whitespace
+ // * paths sharing a common prefix with another directory
+ void TerminalSettingsTests::NormalizeCommandLine()
+ {
+ using namespace std::string_literals;
+
+ static constexpr auto touch = [](const auto& path) {
+ std::ofstream file{ path };
+ };
+
+ std::wstring guid;
+ {
+ GUID g{};
+ THROW_IF_FAILED(CoCreateGuid(&g));
+ guid = fmt::format(
+ L"{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
+ g.Data1,
+ g.Data2,
+ g.Data3,
+ g.Data4[0],
+ g.Data4[1],
+ g.Data4[2],
+ g.Data4[3],
+ g.Data4[4],
+ g.Data4[5],
+ g.Data4[6],
+ g.Data4[7]);
+ }
+
+ const auto tmpdir = std::filesystem::temp_directory_path();
+ const auto dir1 = tmpdir / guid;
+ const auto dir2 = tmpdir / (guid + L" two");
+ const auto file1 = dir1 / L"file 1.exe";
+ const auto file2 = dir2 / L"file 2.exe";
+
+ const auto cleanup = wil::scope_exit([&]() {
+ std::error_code ec;
+ remove_all(dir1, ec);
+ remove_all(dir2, ec);
+ });
+
+ create_directory(dir1);
+ create_directory(dir2);
+ touch(file1);
+ touch(file2);
+
+ {
+ const auto commandLine = file2.native() + LR"( -foo "bar1 bar2" -baz)"s;
+ const auto expected = file2.native() + L"\0-foo\0bar1 bar2\0-baz"s;
+ const auto actual = implementation::CascadiaSettings::NormalizeCommandLine(commandLine.c_str());
+ VERIFY_ARE_EQUAL(expected, actual);
+ }
+ {
+ const auto commandLine = L"C:\\";
+ const auto expected = L"C:\\";
+ const auto actual = implementation::CascadiaSettings::NormalizeCommandLine(commandLine);
+ VERIFY_ARE_EQUAL(expected, actual);
+ }
+ }
+
void TerminalSettingsTests::GetProfileForArgsWithCommandline()
{
// I'm exclusively using cmd.exe as I know exactly where it resides at.
@@ -145,6 +209,10 @@ namespace SettingsModelLocalTests
"guid": "{6239a42c-3333-49a3-80bd-e8fdd045185c}",
"commandline": "cmd.exe /A /C",
"connectionType": "{9a9977a7-1fe0-49c0-b6c0-13a0cd1c98a1}"
+ },
+ {
+ "guid": "{6239a42c-4444-49a3-80bd-e8fdd045185c}",
+ "commandline": "C:\\invalid.exe",
}
]
}
@@ -163,7 +231,7 @@ namespace SettingsModelLocalTests
TestCase{ L"cmd.exe", 0 },
// SearchPathW() normalization + case insensitive matching.
TestCase{ L"cmd.exe /a", 1 },
- TestCase{ L"C:\\Windows\\System32\\cmd.exe /A", 1 },
+ TestCase{ L"%SystemRoot%\\System32\\cmd.exe /A", 1 },
// Test that we don't pick the equally long but different "/A /B" variant.
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A /C", 1 },
// Test that we don't pick the shorter "/A" variant,
@@ -173,6 +241,9 @@ namespace SettingsModelLocalTests
// Ignore profiles with a connection type, like the Azure cloud shell.
// Instead it should pick any other prefix.
TestCase{ L"C:\\Windows\\System32\\cmd.exe /A /C", 1 },
+ // Failure to normalize a path (e.g. because the path doesn't exist)
+ // should yield the unmodified input string (see NormalizeCommandLine).
+ TestCase{ L"C:\\invalid.exe /A /B", 4 },
// Return base layer profile for missing profiles.
TestCase{ L"C:\\Windows\\regedit.exe", -1 },
};
diff --git a/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj b/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj
index 6217790a895..d44431a5f89 100644
--- a/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj
+++ b/src/cascadia/LocalTests_TerminalApp/TerminalApp.LocalTests.vcxproj
@@ -92,11 +92,11 @@
x86$(Platform)
- <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\runtimes\win10-$(Native-Platform)\native\"
+ <_MUXBinRoot>"$(OpenConsoleDir)packages\Microsoft.UI.Xaml.$(TerminalMUXVersion)\runtimes\win10-$(Native-Platform)\native\"
-
+
diff --git a/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj b/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj
index 5197b0bd07f..a97fe8064b4 100644
--- a/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj
+++ b/src/cascadia/LocalTests_TerminalApp/TestHostApp/TestHostApp.vcxproj
@@ -123,7 +123,7 @@
-
+
diff --git a/src/cascadia/Remoting/WindowManager.cpp b/src/cascadia/Remoting/WindowManager.cpp
index 4cafee145a0..8ce04464cda 100644
--- a/src/cascadia/Remoting/WindowManager.cpp
+++ b/src/cascadia/Remoting/WindowManager.cpp
@@ -252,8 +252,11 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
if (_peasant)
{
- // Inform the monarch of the time we were last activated
- _monarch.HandleActivatePeasant(_peasant.GetLastActivatedArgs());
+ if (const auto& lastActivated{ _peasant.GetLastActivatedArgs() })
+ {
+ // Inform the monarch of the time we were last activated
+ _monarch.HandleActivatePeasant(lastActivated);
+ }
}
if (!_isKing)
@@ -539,10 +542,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
void WindowManager::SummonAllWindows()
{
- if constexpr (Feature_NotificationIcon::IsEnabled())
- {
- _monarch.SummonAllWindows();
- }
+ _monarch.SummonAllWindows();
}
Windows::Foundation::Collections::IVectorView WindowManager::GetPeasantInfos()
diff --git a/src/cascadia/Remoting/packages.config b/src/cascadia/Remoting/packages.config
index 2d79f9f5adb..64e09e4c8e5 100644
--- a/src/cascadia/Remoting/packages.config
+++ b/src/cascadia/Remoting/packages.config
@@ -1,5 +1,5 @@
-
+
diff --git a/src/cascadia/TerminalApp/ActionPreviewHandlers.cpp b/src/cascadia/TerminalApp/ActionPreviewHandlers.cpp
index c43dcdf399a..84aba407f74 100644
--- a/src/cascadia/TerminalApp/ActionPreviewHandlers.cpp
+++ b/src/cascadia/TerminalApp/ActionPreviewHandlers.cpp
@@ -70,12 +70,14 @@ namespace winrt::TerminalApp::implementation
// Apply the reverts in reverse order - If we had multiple previews
// stacked on top of each other, then this will ensure the first one in
// is the last one out.
- for (auto i{ _restorePreviewFuncs.rbegin() }; i < _restorePreviewFuncs.rend(); i++)
+ const auto cleanup = wil::scope_exit([this]() {
+ _restorePreviewFuncs.clear();
+ });
+
+ for (const auto& f : _restorePreviewFuncs)
{
- auto f = *i;
f();
}
- _restorePreviewFuncs.clear();
}
// Method Description:
@@ -94,6 +96,8 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& scheme{ _settings.GlobalSettings().ColorSchemes().TryLookup(args.SchemeName()) })
{
+ const auto backup = _restorePreviewFuncs.empty();
+
_ApplyToActiveControls([&](const auto& control) {
// Stash a copy of the current scheme.
auto originalScheme{ control.ColorScheme() };
@@ -101,34 +105,38 @@ namespace winrt::TerminalApp::implementation
// Apply the new scheme.
control.ColorScheme(scheme.ToCoreScheme());
- // Each control will emplace a revert into the
- // _restorePreviewFuncs for itself.
- _restorePreviewFuncs.emplace_back([=]() {
- // On dismiss, restore the original scheme.
- control.ColorScheme(originalScheme);
- });
+ if (backup)
+ {
+ // Each control will emplace a revert into the
+ // _restorePreviewFuncs for itself.
+ _restorePreviewFuncs.emplace_back([=]() {
+ // On dismiss, restore the original scheme.
+ control.ColorScheme(originalScheme);
+ });
+ }
});
}
}
void TerminalPage::_PreviewAdjustOpacity(const Settings::Model::AdjustOpacityArgs& args)
{
- // Clear the saved preview funcs because we don't need to add a restore each time
- // the preview changes, we only need to be able to restore the last one.
- _restorePreviewFuncs.clear();
+ const auto backup = _restorePreviewFuncs.empty();
_ApplyToActiveControls([&](const auto& control) {
// Stash a copy of the original opacity.
auto originalOpacity{ control.BackgroundOpacity() };
// Apply the new opacity
- control.AdjustOpacity(args.Opacity(), args.Relative());
+ control.AdjustOpacity(args.Opacity() / 100.0, args.Relative());
- _restorePreviewFuncs.emplace_back([=]() {
- // On dismiss:
- // Don't adjust relatively, just set outright.
- control.AdjustOpacity(::base::saturated_cast(originalOpacity * 100), false);
- });
+ if (backup)
+ {
+ _restorePreviewFuncs.emplace_back([=]() {
+ // On dismiss:
+ // Don't adjust relatively, just set outright.
+ control.AdjustOpacity(originalOpacity, false);
+ });
+ }
});
}
diff --git a/src/cascadia/TerminalApp/App.xaml b/src/cascadia/TerminalApp/App.xaml
index 251028dee8f..074aed6ab1c 100644
--- a/src/cascadia/TerminalApp/App.xaml
+++ b/src/cascadia/TerminalApp/App.xaml
@@ -21,7 +21,7 @@
+ ControlsResourcesVersion="Version2" />
+
+
+ Color="#202020" />
+
+
+
-
+
+
+ Color="#E8E8E8" />
-
+
diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp
index c8dbacbcbde..dd01c2a2e22 100644
--- a/src/cascadia/TerminalApp/AppActionHandlers.cpp
+++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp
@@ -709,7 +709,6 @@ namespace winrt::TerminalApp::implementation
// This might cause a UAC prompt. The elevation is performed on a
// background thread, as to not block the UI thread.
// Arguments:
- // - elevate: If true, launch the new Terminal elevated using `runas`
// - newTerminalArgs: A NewTerminalArgs describing the terminal instance
// that should be spawned. The Profile should be filled in with the GUID
// of the profile we want to launch.
@@ -717,8 +716,7 @@ namespace winrt::TerminalApp::implementation
// -
// Important: Don't take the param by reference, since we'll be doing work
// on another thread.
- fire_and_forget TerminalPage::_OpenNewWindow(const bool elevate,
- const NewTerminalArgs newTerminalArgs)
+ fire_and_forget TerminalPage::_OpenNewWindow(const NewTerminalArgs newTerminalArgs)
{
// Hop to the BG thread
co_await winrt::resume_background();
@@ -745,9 +743,8 @@ namespace winrt::TerminalApp::implementation
SHELLEXECUTEINFOW seInfo{ 0 };
seInfo.cbSize = sizeof(seInfo);
seInfo.fMask = SEE_MASK_NOASYNC;
- // `runas` will cause the shell to launch this child process elevated.
// `open` will just run the executable normally.
- seInfo.lpVerb = elevate ? L"runas" : L"open";
+ seInfo.lpVerb = L"open";
seInfo.lpFile = exePath.c_str();
seInfo.lpParameters = cmdline.c_str();
seInfo.nShow = SW_SHOWNORMAL;
@@ -781,7 +778,7 @@ namespace winrt::TerminalApp::implementation
// Manually fill in the evaluated profile.
newTerminalArgs.Profile(::Microsoft::Console::Utils::GuidToString(profile.Guid()));
- _OpenNewWindow(false, newTerminalArgs);
+ _OpenNewWindow(newTerminalArgs);
actionArgs.Handled(true);
}
@@ -923,7 +920,10 @@ namespace winrt::TerminalApp::implementation
// If we didn't have args, or the args weren't ExportBufferArgs (somehow)
_ExportTab(*activeTab, L"");
- args.Handled(true);
+ if (args)
+ {
+ args.Handled(true);
+ }
}
}
@@ -967,7 +967,7 @@ namespace winrt::TerminalApp::implementation
if (const auto& realArgs = args.ActionArgs().try_as())
{
const auto res = _ApplyToActiveControls([&](auto& control) {
- control.AdjustOpacity(realArgs.Opacity(), realArgs.Relative());
+ control.AdjustOpacity(realArgs.Opacity() / 100.0, realArgs.Relative());
});
args.Handled(res);
}
diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp
index ec6ebf50fc5..71698f7c4c2 100644
--- a/src/cascadia/TerminalApp/AppLogic.cpp
+++ b/src/cascadia/TerminalApp/AppLogic.cpp
@@ -396,6 +396,14 @@ namespace winrt::TerminalApp::implementation
}
}
+ // Method Description:
+ // - Returns true if there is no dialog currently being shown (meaning that we can show a dialog)
+ // - Returns false if there is a dialog currently being shown (meaning that we cannot show another dialog)
+ bool AppLogic::CanShowDialog()
+ {
+ return (_dialog == nullptr);
+ }
+
// Method Description:
// - Displays a dialog for errors found while loading or validating the
// settings. Uses the resources under the provided title and content keys
@@ -504,8 +512,26 @@ namespace winrt::TerminalApp::implementation
if (keyboardServiceIsDisabled)
{
_root->ShowKeyboardServiceWarning();
+
+ TraceLoggingWrite(
+ g_hTerminalAppProvider,
+ "KeyboardServiceWasDisabled",
+ TraceLoggingDescription("Event emitted when the keyboard service is disabled, and we warned them about it"),
+ TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
+ TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
}
}
+ else
+ {
+ // For when the warning was disabled in the settings
+
+ TraceLoggingWrite(
+ g_hTerminalAppProvider,
+ "KeyboardServiceWarningWasDisabledBySetting",
+ TraceLoggingDescription("Event emitted when the user has disabled the KB service warning"),
+ TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
+ TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
+ }
if (FAILED(_settingsLoadedResult))
{
@@ -1074,18 +1100,18 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Gets the title of the currently focused terminal control. If there
- // isn't a control selected for any reason, returns "Windows Terminal"
+ // isn't a control selected for any reason, returns "Terminal"
// Arguments:
// -
// Return Value:
- // - the title of the focused control if there is one, else "Windows Terminal"
+ // - the title of the focused control if there is one, else "Terminal"
hstring AppLogic::Title()
{
if (_root)
{
return _root->Title();
}
- return { L"Windows Terminal" };
+ return { L"Terminal" };
}
// Method Description:
@@ -1472,6 +1498,24 @@ namespace winrt::TerminalApp::implementation
return _root != nullptr ? _root->ShouldUsePersistedLayout(_settings) : false;
}
+ bool AppLogic::ShouldImmediatelyHandoffToElevated()
+ {
+ if (!_loadedInitialSettings)
+ {
+ // Load settings if we haven't already
+ LoadSettings();
+ }
+
+ return _root != nullptr ? _root->ShouldImmediatelyHandoffToElevated(_settings) : false;
+ }
+ void AppLogic::HandoffToElevated()
+ {
+ if (_root)
+ {
+ _root->HandoffToElevated(_settings);
+ }
+ }
+
void AppLogic::SaveWindowLayoutJsons(const Windows::Foundation::Collections::IVector& layouts)
{
std::vector converted;
@@ -1569,38 +1613,24 @@ namespace winrt::TerminalApp::implementation
bool AppLogic::GetMinimizeToNotificationArea()
{
- if constexpr (Feature_NotificationIcon::IsEnabled())
- {
- if (!_loadedInitialSettings)
- {
- // Load settings if we haven't already
- LoadSettings();
- }
-
- return _settings.GlobalSettings().MinimizeToNotificationArea();
- }
- else
+ if (!_loadedInitialSettings)
{
- return false;
+ // Load settings if we haven't already
+ LoadSettings();
}
+
+ return _settings.GlobalSettings().MinimizeToNotificationArea();
}
bool AppLogic::GetAlwaysShowNotificationIcon()
{
- if constexpr (Feature_NotificationIcon::IsEnabled())
- {
- if (!_loadedInitialSettings)
- {
- // Load settings if we haven't already
- LoadSettings();
- }
-
- return _settings.GlobalSettings().AlwaysShowNotificationIcon();
- }
- else
+ if (!_loadedInitialSettings)
{
- return false;
+ // Load settings if we haven't already
+ LoadSettings();
}
+
+ return _settings.GlobalSettings().AlwaysShowNotificationIcon();
}
bool AppLogic::GetShowTitleInTitlebar()
diff --git a/src/cascadia/TerminalApp/AppLogic.h b/src/cascadia/TerminalApp/AppLogic.h
index 19e891843b9..582866704b4 100644
--- a/src/cascadia/TerminalApp/AppLogic.h
+++ b/src/cascadia/TerminalApp/AppLogic.h
@@ -81,6 +81,8 @@ namespace winrt::TerminalApp::implementation
bool AlwaysOnTop() const;
bool ShouldUsePersistedLayout();
+ bool ShouldImmediatelyHandoffToElevated();
+ void HandoffToElevated();
hstring GetWindowLayoutJson(Microsoft::Terminal::Settings::Model::LaunchPosition position);
void SaveWindowLayoutJsons(const Windows::Foundation::Collections::IVector& layouts);
void IdentifyWindow();
@@ -120,6 +122,7 @@ namespace winrt::TerminalApp::implementation
bool GetShowTitleInTitlebar();
winrt::Windows::Foundation::IAsyncOperation ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
+ bool CanShowDialog();
void DismissDialog();
Windows::Foundation::Collections::IMapView GlobalHotkeys();
diff --git a/src/cascadia/TerminalApp/AppLogic.idl b/src/cascadia/TerminalApp/AppLogic.idl
index 9121c3ccf9e..df0f7b3cd47 100644
--- a/src/cascadia/TerminalApp/AppLogic.idl
+++ b/src/cascadia/TerminalApp/AppLogic.idl
@@ -33,6 +33,8 @@ namespace TerminalApp
SystemMenuItemHandler Handler { get; };
};
+ // See IDialogPresenter and TerminalPage's DialogPresenter for more
+ // information.
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter
{
AppLogic();
@@ -93,6 +95,8 @@ namespace TerminalApp
TaskbarState TaskbarState{ get; };
Boolean ShouldUsePersistedLayout();
+ Boolean ShouldImmediatelyHandoffToElevated();
+ void HandoffToElevated();
String GetWindowLayoutJson(Microsoft.Terminal.Settings.Model.LaunchPosition position);
void SaveWindowLayoutJsons(Windows.Foundation.Collections.IVector layouts);
@@ -104,11 +108,6 @@ namespace TerminalApp
Windows.Foundation.Collections.IMapView GlobalHotkeys();
- // See IDialogPresenter and TerminalPage's DialogPresenter for more
- // information.
- Windows.Foundation.IAsyncOperation ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
- void DismissDialog();
-
event Windows.Foundation.TypedEventHandler
-
-
-
-
-
-
-
-
-
-
-
-
-
14.013,0,0,00,24,0,0250
+ 1000
@@ -70,16 +49,24 @@
+
+
@@ -93,7 +80,7 @@
@@ -122,6 +109,7 @@
TargetType="Button">
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.cpp b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.cpp
index 9d6c0e08849..fd9aa78d4f4 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.cpp
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.cpp
@@ -24,6 +24,23 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// --> "und" is synonymous for "Use system language".
constexpr std::wstring_view systemLanguageTag{ L"und" };
+ static constexpr std::array appLanguageTags{
+ L"en-US",
+ L"de-DE",
+ L"es-ES",
+ L"fr-FR",
+ L"it-IT",
+ L"ja",
+ L"ko",
+ L"pt-BR",
+ L"qps-PLOC",
+ L"qps-PLOCA",
+ L"qps-PLOCM",
+ L"ru",
+ L"zh-Hans-CN",
+ L"zh-Hant-TW",
+ };
+
GlobalAppearance::GlobalAppearance()
{
InitializeComponent();
@@ -88,43 +105,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// [1]:
{
// ManifestLanguages contains languages the app ships with.
- //
- // Languages is a computed list that merges the ManifestLanguages with the
- // user's ranked list of preferred languages taken from the system settings.
- // As is tradition the API documentation is incomplete though, as it can also
- // contain regional language variants. If our app supports en-US, but the user
- // has en-GB or en-DE in their system's preferred language list, Languages will
- // contain those as well, as they're variants from a supported language. We should
- // allow a user to select those, as regional formattings can vary significantly.
- const std::array tagSources{
- winrt::Windows::Globalization::ApplicationLanguages::ManifestLanguages(),
- winrt::Windows::Globalization::ApplicationLanguages::Languages()
- };
-
- // tags will hold all the flattened results from tagSources.
- // We resize() the vector to the proper size in order to efficiently GetMany() all items.
- tags.resize(std::accumulate(
- tagSources.begin(),
- tagSources.end(),
- // tags[0] will be "und" - the "Use system language" item
- // tags[1..n] will contain tags from tagSources.
- // --> totalTags is offset by 1
- 1,
- [](uint32_t sum, const auto& v) -> uint32_t {
- return sum + v.Size();
- }));
+ // Unfortunately, we cannot use this source. Our manifest must contain the
+ // ~100 languages that are localized for the shell extension and start menu
+ // presentation so we align with Windows display languages for those surfaces.
+ // However, the actual content of our application is limited to a much smaller
+ // subset of approximately 14 languages. As such, we will code the limited
+ // subset of languages that we support for selection within the Settings
+ // dropdown to steer users towards the ones that we can display in the app.
// As per the function definition, the first item
// is always "Use system language" ("und").
- auto data = tags.data();
- *data++ = systemLanguageTag;
+ tags.emplace_back(systemLanguageTag);
- // Finally GetMany() all the tags from tagSources.
- for (const auto& v : tagSources)
+ // Add our hardcoded languages after the system definition.
+ for (const auto& v : appLanguageTags)
{
- const auto size = v.Size();
- v.GetMany(0, winrt::array_view(data, size));
- data += size;
+ tags.push_back(v);
}
}
@@ -199,8 +195,4 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}
- bool GlobalAppearance::FeatureNotificationIconEnabled() const noexcept
- {
- return Feature_NotificationIcon::IsEnabled();
- }
}
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.h b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.h
index dd8b56fa242..7e48178baf4 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.h
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.h
@@ -25,11 +25,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void OnNavigatedTo(const winrt::Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
- bool FeatureNotificationIconEnabled() const noexcept;
-
WINRT_PROPERTY(Editor::GlobalAppearancePageNavigationState, State, nullptr);
- GETSET_BINDABLE_ENUM_SETTING(Theme, winrt::Windows::UI::Xaml::ElementTheme, State().Globals(), Theme);
- GETSET_BINDABLE_ENUM_SETTING(TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, State().Globals(), TabWidthMode);
+ GETSET_BINDABLE_ENUM_SETTING(Theme, winrt::Windows::UI::Xaml::ElementTheme, State().Globals().Theme);
+ GETSET_BINDABLE_ENUM_SETTING(TabWidthMode, winrt::Microsoft::UI::Xaml::Controls::TabViewWidthMode, State().Globals().TabWidthMode);
public:
// LanguageDisplayConverter maps the given BCP 47 tag to a localized string.
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.idl b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.idl
index 9840a4a3d68..7e3483140ab 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.idl
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.idl
@@ -25,7 +25,5 @@ namespace Microsoft.Terminal.Settings.Editor
IInspectable CurrentTabWidthMode;
Windows.Foundation.Collections.IObservableVector TabWidthModeList { get; };
-
- Boolean FeatureNotificationIconEnabled { get; };
}
}
diff --git a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
index 7361ec7cb8a..2a0bdbcb98a 100644
--- a/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
+++ b/src/cascadia/TerminalSettingsEditor/GlobalAppearance.xaml
@@ -28,7 +28,6 @@
@@ -41,7 +40,8 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/Interaction.h b/src/cascadia/TerminalSettingsEditor/Interaction.h
index b541dc394f6..6ce233a08f4 100644
--- a/src/cascadia/TerminalSettingsEditor/Interaction.h
+++ b/src/cascadia/TerminalSettingsEditor/Interaction.h
@@ -26,8 +26,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
WINRT_PROPERTY(Editor::InteractionPageNavigationState, State, nullptr);
- GETSET_BINDABLE_ENUM_SETTING(TabSwitcherMode, Model::TabSwitcherMode, State().Globals(), TabSwitcherMode);
- GETSET_BINDABLE_ENUM_SETTING(CopyFormat, winrt::Microsoft::Terminal::Control::CopyFormat, State().Globals(), CopyFormatting);
+ GETSET_BINDABLE_ENUM_SETTING(TabSwitcherMode, Model::TabSwitcherMode, State().Globals().TabSwitcherMode);
+ GETSET_BINDABLE_ENUM_SETTING(CopyFormat, winrt::Microsoft::Terminal::Control::CopyFormat, State().Globals().CopyFormatting);
};
}
diff --git a/src/cascadia/TerminalSettingsEditor/Interaction.xaml b/src/cascadia/TerminalSettingsEditor/Interaction.xaml
index 8bdf829f65b..8c0e7a08060 100644
--- a/src/cascadia/TerminalSettingsEditor/Interaction.xaml
+++ b/src/cascadia/TerminalSettingsEditor/Interaction.xaml
@@ -27,13 +27,14 @@
-
-
+
+
-
+
-
+
-
+
-
+
@@ -59,11 +64,13 @@
-
+
-
+
-
+
-
+
diff --git a/src/cascadia/TerminalSettingsEditor/Launch.cpp b/src/cascadia/TerminalSettingsEditor/Launch.cpp
index d5c232faa35..7280e7d746b 100644
--- a/src/cascadia/TerminalSettingsEditor/Launch.cpp
+++ b/src/cascadia/TerminalSettingsEditor/Launch.cpp
@@ -73,9 +73,4 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return winrt::single_threaded_observable_vector(std::move(profiles));
}
-
- bool Launch::ShowFirstWindowPreference() const noexcept
- {
- return Feature_PersistedWindowLayout::IsEnabled();
- }
}
diff --git a/src/cascadia/TerminalSettingsEditor/Launch.h b/src/cascadia/TerminalSettingsEditor/Launch.h
index 1a439ba3d65..1302808cd0a 100644
--- a/src/cascadia/TerminalSettingsEditor/Launch.h
+++ b/src/cascadia/TerminalSettingsEditor/Launch.h
@@ -29,13 +29,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void CurrentDefaultProfile(const IInspectable& value);
winrt::Windows::Foundation::Collections::IObservableVector DefaultProfiles() const;
- bool ShowFirstWindowPreference() const noexcept;
-
WINRT_PROPERTY(Editor::LaunchPageNavigationState, State, nullptr);
- GETSET_BINDABLE_ENUM_SETTING(FirstWindowPreference, Model::FirstWindowPreference, State().Settings().GlobalSettings(), FirstWindowPreference);
- GETSET_BINDABLE_ENUM_SETTING(LaunchMode, Model::LaunchMode, State().Settings().GlobalSettings(), LaunchMode);
- GETSET_BINDABLE_ENUM_SETTING(WindowingBehavior, Model::WindowingMode, State().Settings().GlobalSettings(), WindowingBehavior);
+ GETSET_BINDABLE_ENUM_SETTING(FirstWindowPreference, Model::FirstWindowPreference, State().Settings().GlobalSettings().FirstWindowPreference);
+ GETSET_BINDABLE_ENUM_SETTING(LaunchMode, Model::LaunchMode, State().Settings().GlobalSettings().LaunchMode);
+ GETSET_BINDABLE_ENUM_SETTING(WindowingBehavior, Model::WindowingMode, State().Settings().GlobalSettings().WindowingBehavior);
};
}
diff --git a/src/cascadia/TerminalSettingsEditor/Launch.idl b/src/cascadia/TerminalSettingsEditor/Launch.idl
index 1dfc9e86bb5..e7ba647d1dc 100644
--- a/src/cascadia/TerminalSettingsEditor/Launch.idl
+++ b/src/cascadia/TerminalSettingsEditor/Launch.idl
@@ -20,9 +20,6 @@ namespace Microsoft.Terminal.Settings.Editor
// https://github.com/microsoft/microsoft-ui-xaml/issues/5395
IObservableVector DefaultProfiles { get; };
-
- Boolean ShowFirstWindowPreference { get; };
-
IInspectable CurrentFirstWindowPreference;
IObservableVector FirstWindowPreferenceList { get; };
diff --git a/src/cascadia/TerminalSettingsEditor/Launch.xaml b/src/cascadia/TerminalSettingsEditor/Launch.xaml
index 67a4a44d018..308ce6a10ab 100644
--- a/src/cascadia/TerminalSettingsEditor/Launch.xaml
+++ b/src/cascadia/TerminalSettingsEditor/Launch.xaml
@@ -37,8 +37,7 @@
-
+
@@ -130,12 +132,13 @@
-
+
+ Style="{StaticResource ExpanderSettingContainerStyle}">
+ x:Uid="Globals_LaunchMode"
+ Style="{StaticResource ExpanderSettingContainerStyle}">
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.cpp b/src/cascadia/TerminalSettingsEditor/MainPage.cpp
index 1575b0c4884..08855aa0336 100644
--- a/src/cascadia/TerminalSettingsEditor/MainPage.cpp
+++ b/src/cascadia/TerminalSettingsEditor/MainPage.cpp
@@ -28,6 +28,7 @@ using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI::Xaml::Controls;
+using namespace winrt::Windows::Foundation::Collections;
static const std::wstring_view launchTag{ L"Launch_Nav" };
static const std::wstring_view interactionTag{ L"Interaction_Nav" };
@@ -58,6 +59,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Automation::AutomationProperties::SetHelpText(SaveButton(), RS_(L"Settings_SaveSettingsButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
Automation::AutomationProperties::SetHelpText(ResetButton(), RS_(L"Settings_ResetSettingsButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
Automation::AutomationProperties::SetHelpText(OpenJsonNavItem(), RS_(L"Nav_OpenJSON/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
+
+ _breadcrumbs = single_threaded_observable_vector();
}
// Method Description:
@@ -72,16 +75,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_settingsClone = settings.Copy();
// Deduce information about the currently selected item
- IInspectable selectedItemTag;
- auto menuItems{ SettingsNav().MenuItems() };
- if (const auto& selectedItem{ SettingsNav().SelectedItem() })
+ IInspectable lastBreadcrumb;
+ const auto size = _breadcrumbs.Size();
+ if (size > 0)
{
- if (const auto& navViewItem{ selectedItem.try_as() })
- {
- selectedItemTag = navViewItem.Tag();
- }
+ lastBreadcrumb = _breadcrumbs.GetAt(size - 1);
}
+ auto menuItems{ SettingsNav().MenuItems() };
+
// We'll remove a bunch of items and iterate over it twice.
// --> Copy it into an STL vector to simplify our code and reduce COM overhead.
std::vector menuItemsSTL(menuItems.Size(), nullptr);
@@ -128,8 +130,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// We'll update the profile in the _profilesNavState whenever we actually navigate to one
// now that the menuItems are repopulated,
- // refresh the current page using the SelectedItem data we collected before the refresh
- if (selectedItemTag)
+ // refresh the current page using the breadcrumb data we collected before the refresh
+ if (const auto& crumb{ lastBreadcrumb.try_as() })
{
for (const auto& item : menuItems)
{
@@ -139,26 +141,26 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
if (const auto& stringTag{ tag.try_as() })
{
- if (const auto& selectedItemStringTag{ selectedItemTag.try_as() })
+ if (const auto& breadcrumbStringTag{ crumb->Tag().try_as() })
{
- if (stringTag == selectedItemStringTag)
+ if (stringTag == breadcrumbStringTag)
{
// found the one that was selected before the refresh
SettingsNav().SelectedItem(item);
- _Navigate(*stringTag);
+ _Navigate(*stringTag, crumb->SubPage());
return;
}
}
}
else if (const auto& profileTag{ tag.try_as() })
{
- if (const auto& selectedItemProfileTag{ selectedItemTag.try_as() })
+ if (const auto& breadcrumbProfileTag{ crumb->Tag().try_as() })
{
- if (profileTag->OriginalProfileGuid() == selectedItemProfileTag->OriginalProfileGuid())
+ if (profileTag->OriginalProfileGuid() == breadcrumbProfileTag->OriginalProfileGuid())
{
// found the one that was selected before the refresh
SettingsNav().SelectedItem(item);
- _Navigate(*profileTag);
+ _Navigate(*profileTag, crumb->SubPage());
return;
}
}
@@ -173,7 +175,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// We can use menuItemsSTL here because the only things they miss are profile entries.
const auto& firstItem{ menuItemsSTL.at(0).as() };
SettingsNav().SelectedItem(firstItem);
- _Navigate(unbox_value(firstItem.Tag()));
+ _Navigate(unbox_value(firstItem.Tag()), BreadcrumbSubPage::None);
}
void MainPage::SetHostingWindow(uint64_t hostingWindow) noexcept
@@ -242,7 +244,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Manually navigate because setting the selected item programmatically doesn't trigger ItemInvoked.
if (const auto tag = initialItem.as().Tag())
{
- _Navigate(unbox_value(tag));
+ _Navigate(unbox_value(tag), BreadcrumbSubPage::None);
}
}
}
@@ -266,33 +268,96 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (const auto navString = clickedItemContainer.Tag().try_as())
{
- _Navigate(*navString);
+ _Navigate(*navString, BreadcrumbSubPage::None);
}
else if (const auto profile = clickedItemContainer.Tag().try_as())
{
// Navigate to a page with the given profile
- _Navigate(profile);
+ _Navigate(profile, BreadcrumbSubPage::None);
}
}
}
- void MainPage::_Navigate(hstring clickedItemTag)
+ void MainPage::_PreNavigateHelper()
+ {
+ _profileViewModelChangedRevoker.revoke();
+ _breadcrumbs.Clear();
+ }
+
+ void MainPage::_SetupProfileEventHandling(const Editor::ProfilePageNavigationState state)
+ {
+ // Add an event handler to navigate to Profiles_Appearance or Profiles_Advanced
+ // Some notes on this:
+ // - At first we tried putting another frame inside Profiles.xaml and having that
+ // frame default to showing Profiles_Base. This allowed the logic for navigation
+ // to Profiles_Advanced/Profiles_Appearance to live within Profiles.cpp.
+ // - However, the header for the SUI lives in MainPage.xaml (because that's where
+ // the whole NavigationView is) and so the BreadcrumbBar needs to be in MainPage.xaml.
+ // We decided that it's better for the owner of the BreadcrumbBar to also be responsible
+ // for navigation, so the navigation to Profiles_Advanced/Profiles_Appearance from
+ // Profiles_Base got moved here.
+ const auto profile = state.Profile();
+
+ // If this is the base layer, the breadcrumb tag should be the globalProfileTag instead of the
+ // ProfileViewModel, because the navigation menu item for this profile is the globalProfileTag.
+ // See MainPage::UpdateSettings for why this matters
+ const auto breadcrumbTag = profile.IsBaseLayer() ? box_value(globalProfileTag) : box_value(profile);
+ const auto breadcrumbText = profile.IsBaseLayer() ? RS_(L"Nav_ProfileDefaults/Content") : profile.Name();
+ _profileViewModelChangedRevoker = profile.PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
+ const auto settingName{ args.PropertyName() };
+ if (settingName == L"CurrentPage")
+ {
+ const auto currentPage = profile.CurrentPage();
+ if (currentPage == ProfileSubPage::Base)
+ {
+ contentFrame().Navigate(xaml_typename(), state);
+ _breadcrumbs.Clear();
+ const auto crumb = winrt::make(breadcrumbTag, breadcrumbText, BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
+ }
+ else if (currentPage == ProfileSubPage::Appearance)
+ {
+ contentFrame().Navigate(xaml_typename(), state);
+ const auto crumb = winrt::make(breadcrumbTag, RS_(L"Profile_Appearance/Header"), BreadcrumbSubPage::Profile_Appearance);
+ _breadcrumbs.Append(crumb);
+ }
+ else if (currentPage == ProfileSubPage::Advanced)
+ {
+ contentFrame().Navigate(xaml_typename(), state);
+ const auto crumb = winrt::make(breadcrumbTag, RS_(L"Profile_Advanced/Header"), BreadcrumbSubPage::Profile_Advanced);
+ _breadcrumbs.Append(crumb);
+ }
+ }
+ });
+ }
+
+ void MainPage::_Navigate(hstring clickedItemTag, BreadcrumbSubPage subPage)
{
+ _PreNavigateHelper();
+
if (clickedItemTag == launchTag)
{
contentFrame().Navigate(xaml_typename(), winrt::make(_settingsClone));
+ const auto crumb = winrt::make(box_value(clickedItemTag), RS_(L"Nav_Launch/Content"), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
}
else if (clickedItemTag == interactionTag)
{
contentFrame().Navigate(xaml_typename(), winrt::make(_settingsClone.GlobalSettings()));
+ const auto crumb = winrt::make(box_value(clickedItemTag), RS_(L"Nav_Interaction/Content"), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
}
else if (clickedItemTag == renderingTag)
{
contentFrame().Navigate(xaml_typename(), winrt::make(_settingsClone.GlobalSettings()));
+ const auto crumb = winrt::make(box_value(clickedItemTag), RS_(L"Nav_Rendering/Content"), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
}
else if (clickedItemTag == actionsTag)
{
contentFrame().Navigate(xaml_typename(), winrt::make(_settingsClone));
+ const auto crumb = winrt::make(box_value(clickedItemTag), RS_(L"Nav_Actions/Content"), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
}
else if (clickedItemTag == globalProfileTag)
{
@@ -302,21 +367,41 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_settingsClone.GlobalSettings().ColorSchemes(),
*this) };
- contentFrame().Navigate(xaml_typename(), state);
+ _SetupProfileEventHandling(state);
+
+ contentFrame().Navigate(xaml_typename(), state);
+ const auto crumb = winrt::make(box_value(clickedItemTag), RS_(L"Nav_ProfileDefaults/Content"), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
+
+ // If we were given a label, make sure we are on the correct sub-page
+ if (subPage == BreadcrumbSubPage::Profile_Appearance)
+ {
+ profileVM.CurrentPage(ProfileSubPage::Appearance);
+ }
+ else if (subPage == BreadcrumbSubPage::Profile_Advanced)
+ {
+ profileVM.CurrentPage(ProfileSubPage::Advanced);
+ }
}
else if (clickedItemTag == colorSchemesTag)
{
contentFrame().Navigate(xaml_typename(), _colorSchemesNavState);
+ const auto crumb = winrt::make(box_value(clickedItemTag), RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
}
else if (clickedItemTag == globalAppearanceTag)
{
contentFrame().Navigate(xaml_typename(), winrt::make(_settingsClone.GlobalSettings()));
+ const auto crumb = winrt::make(box_value(clickedItemTag), RS_(L"Nav_Appearance/Content"), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
}
else if (clickedItemTag == addProfileTag)
{
auto addProfileState{ winrt::make(_settingsClone) };
addProfileState.AddNew({ get_weak(), &MainPage::_AddProfileHandler });
contentFrame().Navigate(xaml_typename(), addProfileState);
+ const auto crumb = winrt::make(box_value(clickedItemTag), RS_(L"Nav_AddNewProfile/Content"), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
}
}
@@ -325,16 +410,37 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// - NOTE: this does not update the selected item.
// Arguments:
// - profile - the profile object we are getting a view of
- void MainPage::_Navigate(const Editor::ProfileViewModel& profile)
+ void MainPage::_Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage)
{
auto state{ winrt::make(profile,
_settingsClone.GlobalSettings().ColorSchemes(),
*this) };
+ _PreNavigateHelper();
+
// Add an event handler for when the user wants to delete a profile.
profile.DeleteProfile({ this, &MainPage::_DeleteProfile });
- contentFrame().Navigate(xaml_typename(), state);
+ _SetupProfileEventHandling(state);
+
+ contentFrame().Navigate(xaml_typename(), state);
+ const auto crumb = winrt::make(box_value(profile), profile.Name(), BreadcrumbSubPage::None);
+ _breadcrumbs.Append(crumb);
+
+ // Set the profile's 'CurrentPage' to the correct one, if this requires further navigation, the
+ // event handler will do it
+ if (subPage == BreadcrumbSubPage::None)
+ {
+ profile.CurrentPage(ProfileSubPage::Base);
+ }
+ else if (subPage == BreadcrumbSubPage::Profile_Appearance)
+ {
+ profile.CurrentPage(ProfileSubPage::Appearance);
+ }
+ else if (subPage == BreadcrumbSubPage::Profile_Advanced)
+ {
+ profile.CurrentPage(ProfileSubPage::Advanced);
+ }
}
void MainPage::OpenJsonTapped(IInspectable const& /*sender*/, Windows::UI::Xaml::Input::TappedRoutedEventArgs const& /*args*/)
@@ -368,6 +474,23 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
UpdateSettings(_settingsSource);
}
+ void MainPage::BreadcrumbBar_ItemClicked(Microsoft::UI::Xaml::Controls::BreadcrumbBar const& /*sender*/, Microsoft::UI::Xaml::Controls::BreadcrumbBarItemClickedEventArgs const& args)
+ {
+ if (gsl::narrow_cast(args.Index()) < (_breadcrumbs.Size() - 1))
+ {
+ const auto tag = args.Item().as()->Tag();
+ const auto subPage = args.Item().as()->SubPage();
+ if (const auto profileViewModel = tag.try_as())
+ {
+ _Navigate(*profileViewModel, subPage);
+ }
+ else
+ {
+ _Navigate(tag.as(), subPage);
+ }
+ }
+ }
+
void MainPage::_InitializeProfilesList()
{
const auto menuItems = SettingsNav().MenuItems();
@@ -381,6 +504,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
if (!profile.Deleted())
{
auto navItem = _CreateProfileNavViewItem(_viewModelForProfile(profile, _settingsClone));
+ Controls::ToolTipService::SetToolTip(navItem, box_value(profile.Name()));
menuItems.Append(navItem);
}
}
@@ -388,6 +512,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Top off (the end of the nav view) with the Add Profile item
MUX::Controls::NavigationViewItem addProfileItem;
addProfileItem.Content(box_value(RS_(L"Nav_AddNewProfile/Content")));
+ Controls::ToolTipService::SetToolTip(addProfileItem, box_value(RS_(L"Nav_AddNewProfile/Content")));
addProfileItem.Tag(box_value(addProfileTag));
FontIcon icon;
@@ -407,7 +532,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// Select and navigate to the new profile
SettingsNav().SelectedItem(navItem);
- _Navigate(profileViewModel);
+ _Navigate(profileViewModel, BreadcrumbSubPage::None);
}
MUX::Controls::NavigationViewItem MainPage::_CreateProfileNavViewItem(const Editor::ProfileViewModel& profile)
@@ -467,7 +592,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// navigate to the profile next to this one
const auto newSelectedItem{ menuItems.GetAt(index < menuItems.Size() - 1 ? index : index - 1) };
SettingsNav().SelectedItem(newSelectedItem);
- _Navigate(newSelectedItem.try_as().Tag().try_as());
+ _Navigate(newSelectedItem.try_as().Tag().try_as(), BreadcrumbSubPage::None);
}
+ IObservableVector MainPage::Breadcrumbs() noexcept
+ {
+ return _breadcrumbs;
+ }
}
diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.h b/src/cascadia/TerminalSettingsEditor/MainPage.h
index faea7353963..2fea7ef72ed 100644
--- a/src/cascadia/TerminalSettingsEditor/MainPage.h
+++ b/src/cascadia/TerminalSettingsEditor/MainPage.h
@@ -4,10 +4,23 @@
#pragma once
#include "MainPage.g.h"
+#include "Breadcrumb.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
+ struct Breadcrumb : BreadcrumbT
+ {
+ Breadcrumb(IInspectable tag, winrt::hstring label, BreadcrumbSubPage subPage) :
+ _Tag{ tag },
+ _Label{ label },
+ _SubPage{ subPage } {}
+
+ WINRT_PROPERTY(IInspectable, Tag);
+ WINRT_PROPERTY(winrt::hstring, Label);
+ WINRT_PROPERTY(BreadcrumbSubPage, SubPage);
+ };
+
struct MainPage : MainPageT
{
MainPage() = delete;
@@ -21,14 +34,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void SettingsNav_ItemInvoked(Microsoft::UI::Xaml::Controls::NavigationView const& sender, Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs const& args);
void SaveButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
void ResetButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
+ void BreadcrumbBar_ItemClicked(Microsoft::UI::Xaml::Controls::BreadcrumbBar const& sender, Microsoft::UI::Xaml::Controls::BreadcrumbBarItemClickedEventArgs const& args);
void SetHostingWindow(uint64_t hostingWindow) noexcept;
bool TryPropagateHostingWindow(IInspectable object) noexcept;
uint64_t GetHostingWindow() const noexcept;
+ Windows::Foundation::Collections::IObservableVector Breadcrumbs() noexcept;
+
TYPED_EVENT(OpenJson, Windows::Foundation::IInspectable, Model::SettingsTarget);
private:
+ Windows::Foundation::Collections::IObservableVector _breadcrumbs;
Model::CascadiaSettings _settingsSource;
Model::CascadiaSettings _settingsClone;
@@ -40,10 +57,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void _DeleteProfile(const Windows::Foundation::IInspectable sender, const Editor::DeleteProfileEventArgs& args);
void _AddProfileHandler(const winrt::guid profileGuid);
- void _Navigate(hstring clickedItemTag);
- void _Navigate(const Editor::ProfileViewModel& profile);
+ void _SetupProfileEventHandling(const winrt::Microsoft::Terminal::Settings::Editor::ProfilePageNavigationState state);
+
+ void _PreNavigateHelper();
+ void _Navigate(hstring clickedItemTag, BreadcrumbSubPage subPage);
+ void _Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage);
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageNavigationState _colorSchemesNavState{ nullptr };
+
+ Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _profileViewModelChangedRevoker;
};
}
diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.idl b/src/cascadia/TerminalSettingsEditor/MainPage.idl
index 2513c8b7b40..4c771419753 100644
--- a/src/cascadia/TerminalSettingsEditor/MainPage.idl
+++ b/src/cascadia/TerminalSettingsEditor/MainPage.idl
@@ -13,6 +13,20 @@ namespace Microsoft.Terminal.Settings.Editor
UInt64 GetHostingWindow();
}
+ enum BreadcrumbSubPage
+ {
+ None = 0,
+ Profile_Appearance,
+ Profile_Advanced
+ };
+
+ runtimeclass Breadcrumb
+ {
+ IInspectable Tag;
+ String Label;
+ BreadcrumbSubPage SubPage;
+ }
+
[default_interface] runtimeclass MainPage : Windows.UI.Xaml.Controls.Page, IHostedInWindow
{
MainPage(Microsoft.Terminal.Settings.Model.CascadiaSettings settings);
@@ -23,5 +37,7 @@ namespace Microsoft.Terminal.Settings.Editor
// Due to the aforementioned bug, we can't use IInitializeWithWindow _here_ either.
// Let's just smuggle the HWND in as a UInt64 :|
void SetHostingWindow(UInt64 window);
+
+ Windows.Foundation.Collections.IObservableVector Breadcrumbs { get; };
}
}
diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.xaml b/src/cascadia/TerminalSettingsEditor/MainPage.xaml
index e243f34e6f9..9fe881938ad 100644
--- a/src/cascadia/TerminalSettingsEditor/MainPage.xaml
+++ b/src/cascadia/TerminalSettingsEditor/MainPage.xaml
@@ -6,6 +6,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
@@ -36,12 +37,36 @@
+
+
+ 15,0,0,0
+
+
+
+
+
+
+
+
+
+
+
+ 28
+ 11,4,12,0
+ SemiBold
+ 16
+
+
+
+
@@ -99,7 +124,7 @@
-
+
-
+
-
+
@@ -130,9 +155,8 @@
diff --git a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
index 4b97bbb87e6..7c5f17695a9 100644
--- a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
+++ b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
@@ -70,13 +70,25 @@
MainPage.xaml
- Profiles.xaml
+ Profiles.idlCodeProfileViewModel.idlCode
+
+ Profiles_Base.xaml
+ Code
+
+
+ Profiles_Advanced.xaml
+ Code
+
+
+ Profiles_Appearance.xaml
+ Code
+ Appearances.xamlCode
@@ -119,7 +131,13 @@
Designer
-
+
+ Designer
+
+
+ Designer
+
+ Designer
@@ -167,14 +185,22 @@
MainPage.xaml
-
- Profiles.xaml
- Code
- ProfileViewModel.idlCode
+
+ Profiles_Base.xaml
+ Code
+
+
+ Profiles_Advanced.xaml
+ Code
+
+
+ Profiles_Appearance.xaml
+ Code
+ Appearances.xamlCode
@@ -230,10 +256,21 @@
MainPage.xaml
- Profiles.xamlCode
+
+ Profiles_Base.xaml
+ Code
+
+
+ Profiles_Advanced.xaml
+ Code
+
+
+ Profiles_Appearance.xaml
+ Code
+ Appearances.xamlCode
@@ -308,12 +345,12 @@
-
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
\ No newline at end of file
diff --git a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
index 1d18fd1f854..b7d94c4b700 100644
--- a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
+++ b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
@@ -35,7 +35,9 @@
-
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp
index 7076b093197..baa44c2bb15 100644
--- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp
+++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp
@@ -70,7 +70,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Windows::Foundation::Collections::IObservableVector ProfileViewModel::_MonospaceFontList{ nullptr };
Windows::Foundation::Collections::IObservableVector ProfileViewModel::_FontList{ nullptr };
- ProfilesPivots ProfileViewModel::_LastActivePivot{ ProfilesPivots::General };
ProfileViewModel::ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& appSettings) :
_profile{ profile },
@@ -115,6 +114,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Opacity(1.0);
}
}
+ else if (viewModelProperty == L"AntialiasingMode")
+ {
+ _NotifyChanges(L"CurrentAntiAliasingMode");
+ }
+ else if (viewModelProperty == L"CloseOnExit")
+ {
+ _NotifyChanges(L"CurrentCloseOnExitMode");
+ }
+ else if (viewModelProperty == L"BellStyle")
+ {
+ _NotifyChanges(L"IsBellStyleFlagSet");
+ }
+ else if (viewModelProperty == L"ScrollState")
+ {
+ _NotifyChanges(L"CurrentScrollState");
+ }
});
// Do the same for the starting directory
diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h
index 0cce255e8c2..925fb567c2b 100644
--- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h
+++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h
@@ -19,9 +19,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
static Windows::Foundation::Collections::IObservableVector CompleteFontList() noexcept { return _FontList; };
static Windows::Foundation::Collections::IObservableVector MonospaceFontList() noexcept { return _MonospaceFontList; };
- static ProfilesPivots LastActivePivot() noexcept { return _LastActivePivot; };
- static void LastActivePivot(Editor::ProfilesPivots val) noexcept { _LastActivePivot = val; };
-
ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& settings);
Model::TerminalSettings TermSettings() const;
void DeleteProfile();
@@ -77,11 +74,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void DeleteUnfocusedAppearance();
bool AtlasEngineAvailable() const noexcept;
- WINRT_PROPERTY(bool, IsBaseLayer, false);
- WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
- GETSET_BINDABLE_ENUM_SETTING(AntiAliasingMode, Microsoft::Terminal::Control::TextAntialiasingMode, _profile, AntialiasingMode);
- GETSET_BINDABLE_ENUM_SETTING(CloseOnExitMode, Microsoft::Terminal::Settings::Model::CloseOnExitMode, _profile, CloseOnExit);
- GETSET_BINDABLE_ENUM_SETTING(ScrollState, Microsoft::Terminal::Control::ScrollbarState, _profile, ScrollState);
+ VIEW_MODEL_OBSERVABLE_PROPERTY(ProfileSubPage, CurrentPage);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, Guid);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, ConnectionType);
@@ -109,6 +102,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing);
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
OBSERVABLE_PROJECTED_SETTING(_profile, UseAtlasEngine);
+ OBSERVABLE_PROJECTED_SETTING(_profile, Elevate);
+
+ WINRT_PROPERTY(bool, IsBaseLayer, false);
+ WINRT_PROPERTY(IHostedInWindow, WindowRoot, nullptr);
+ GETSET_BINDABLE_ENUM_SETTING(AntiAliasingMode, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode);
+ GETSET_BINDABLE_ENUM_SETTING(CloseOnExitMode, Microsoft::Terminal::Settings::Model::CloseOnExitMode, CloseOnExit);
+ GETSET_BINDABLE_ENUM_SETTING(ScrollState, Microsoft::Terminal::Control::ScrollbarState, ScrollState);
TYPED_EVENT(DeleteProfile, Editor::ProfileViewModel, Editor::DeleteProfileEventArgs);
@@ -122,7 +122,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
static Windows::Foundation::Collections::IObservableVector _MonospaceFontList;
static Windows::Foundation::Collections::IObservableVector _FontList;
- static ProfilesPivots _LastActivePivot;
static Editor::Font _GetFont(com_ptr localizedFamilyNames);
diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl
index 7215989d626..8571c7c9441 100644
--- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl
+++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl
@@ -18,9 +18,9 @@ namespace Microsoft.Terminal.Settings.Editor
Guid ProfileGuid { get; };
}
- enum ProfilesPivots
+ enum ProfileSubPage
{
- General = 0,
+ Base = 0,
Appearance = 1,
Advanced = 2
};
@@ -29,7 +29,6 @@ namespace Microsoft.Terminal.Settings.Editor
{
static Windows.Foundation.Collections.IObservableVector CompleteFontList { get; };
static Windows.Foundation.Collections.IObservableVector MonospaceFontList { get; };
- static ProfilesPivots LastActivePivot;
Microsoft.Terminal.Settings.Model.TerminalSettings TermSettings { get; };
@@ -54,6 +53,7 @@ namespace Microsoft.Terminal.Settings.Editor
Boolean CanDeleteProfile { get; };
Boolean IsBaseLayer;
+ ProfileSubPage CurrentPage;
Boolean UseParentProcessDirectory;
Boolean UseCustomStartingDirectory { get; };
AppearanceViewModel DefaultAppearance { get; };
@@ -93,5 +93,6 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, UseAtlasEngine);
+ OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, Elevate);
}
}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.cpp b/src/cascadia/TerminalSettingsEditor/Profiles.cpp
deleted file mode 100644
index 1b54ecb2b62..00000000000
--- a/src/cascadia/TerminalSettingsEditor/Profiles.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-#include "pch.h"
-#include "Profiles.h"
-
-#include "PreviewConnection.h"
-#include "Profiles.g.cpp"
-
-#include
-#include "..\WinRTUtils\inc\Utils.h"
-
-using namespace winrt::Windows::UI::Text;
-using namespace winrt::Windows::UI::Xaml;
-using namespace winrt::Windows::UI::Xaml::Controls;
-using namespace winrt::Windows::UI::Xaml::Data;
-using namespace winrt::Windows::UI::Xaml::Navigation;
-using namespace winrt::Windows::Foundation;
-using namespace winrt::Windows::Foundation::Collections;
-using namespace winrt::Microsoft::Terminal::Settings::Model;
-
-namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
-{
- Profiles::Profiles() :
- _previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make()) }
- {
- InitializeComponent();
-
- const auto startingDirCheckboxTooltip{ ToolTipService::GetToolTip(StartingDirectoryUseParentCheckbox()) };
- Automation::AutomationProperties::SetFullDescription(StartingDirectoryUseParentCheckbox(), unbox_value(startingDirCheckboxTooltip));
-
- Automation::AutomationProperties::SetName(DeleteButton(), RS_(L"Profile_DeleteButton/Text"));
-
- _previewControl.IsEnabled(false);
- _previewControl.AllowFocusWhenDisabled(false);
- ControlPreview().Child(_previewControl);
- }
-
- void Profiles::OnNavigatedTo(const NavigationEventArgs& e)
- {
- auto state{ e.Parameter().as() };
- _Profile = state.Profile();
-
- // generate the font list, if we don't have one
- if (!ProfileViewModel::CompleteFontList() || !ProfileViewModel::MonospaceFontList())
- {
- ProfileViewModel::UpdateFontList();
- }
-
- // Check the use parent directory box if the starting directory is empty
- if (_Profile.StartingDirectory().empty())
- {
- StartingDirectoryUseParentCheckbox().IsChecked(true);
- }
-
- // Subscribe to some changes in the view model
- // These changes should force us to update our own set of "Current" members,
- // and propagate those changes to the UI
- _ViewModelChangedRevoker = _Profile.PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& args) {
- const auto settingName{ args.PropertyName() };
- if (settingName == L"AntialiasingMode")
- {
- _PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentAntiAliasingMode" });
- }
- else if (settingName == L"CloseOnExit")
- {
- _PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentCloseOnExitMode" });
- }
- else if (settingName == L"BellStyle")
- {
- _PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"IsBellStyleFlagSet" });
- }
- else if (settingName == L"ScrollState")
- {
- _PropertyChangedHandlers(*this, PropertyChangedEventArgs{ L"CurrentScrollState" });
- }
- _previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
- });
-
- // The Appearances object handles updating the values in the settings UI, but
- // we still need to listen to the changes here just to update the preview control
- _AppearanceViewModelChangedRevoker = _Profile.DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
- _previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
- });
-
- // Navigate to the pivot in the provided navigation state
- ProfilesPivot().SelectedIndex(static_cast(ProfileViewModel::LastActivePivot()));
-
- // There is a possibility that the control has not fully initialized yet,
- // so wait for it to initialize before updating the settings (so we know
- // that the renderer is set up)
- _previewControl.Initialized([&](auto&& /*s*/, auto&& /*e*/) {
- _previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
- });
- }
-
- void Profiles::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
- {
- _ViewModelChangedRevoker.revoke();
- _AppearanceViewModelChangedRevoker.revoke();
- }
-
- void Profiles::DeleteConfirmation_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
- {
- winrt::get_self(_Profile)->DeleteProfile();
- }
-
- void Profiles::CreateUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
- {
- _Profile.CreateUnfocusedAppearance();
- }
-
- void Profiles::DeleteUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
- {
- _Profile.DeleteUnfocusedAppearance();
- }
-
- fire_and_forget Profiles::Icon_Click(IInspectable const&, RoutedEventArgs const&)
- {
- auto lifetime = get_strong();
-
- const auto parentHwnd{ reinterpret_cast(winrt::get_self(_Profile)->WindowRoot().GetHostingWindow()) };
- auto file = co_await OpenImagePicker(parentHwnd);
- if (!file.empty())
- {
- _Profile.Icon(file);
- }
- }
-
- fire_and_forget Profiles::Commandline_Click(IInspectable const&, RoutedEventArgs const&)
- {
- auto lifetime = get_strong();
-
- static constexpr COMDLG_FILTERSPEC supportedFileTypes[] = {
- { L"Executable Files (*.exe, *.cmd, *.bat)", L"*.exe;*.cmd;*.bat" },
- { L"All Files (*.*)", L"*.*" }
- };
-
- static constexpr winrt::guid clientGuidExecutables{ 0x2E7E4331, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
- const auto parentHwnd{ reinterpret_cast(winrt::get_self(_Profile)->WindowRoot().GetHostingWindow()) };
- auto path = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
- THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExecutables));
- try
- {
- auto folderShellItem{ winrt::capture(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
- dialog->SetDefaultFolder(folderShellItem.get());
- }
- CATCH_LOG(); // non-fatal
- THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
- THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
- THROW_IF_FAILED(dialog->SetDefaultExtension(L"exe;cmd;bat"));
- });
-
- if (!path.empty())
- {
- _Profile.Commandline(path);
- }
- }
-
- fire_and_forget Profiles::StartingDirectory_Click(IInspectable const&, RoutedEventArgs const&)
- {
- auto lifetime = get_strong();
- const auto parentHwnd{ reinterpret_cast(winrt::get_self(_Profile)->WindowRoot().GetHostingWindow()) };
- auto folder = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
- static constexpr winrt::guid clientGuidFolderPicker{ 0xAADAA433, 0xB04D, 0x4BAE, { 0xB1, 0xEA, 0x1E, 0x6C, 0xD1, 0xCD, 0xA6, 0x8B } };
- THROW_IF_FAILED(dialog->SetClientGuid(clientGuidFolderPicker));
- try
- {
- auto folderShellItem{ winrt::capture(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
- dialog->SetDefaultFolder(folderShellItem.get());
- }
- CATCH_LOG(); // non-fatal
-
- DWORD flags{};
- THROW_IF_FAILED(dialog->GetOptions(&flags));
- THROW_IF_FAILED(dialog->SetOptions(flags | FOS_PICKFOLDERS)); // folders only
- });
-
- if (!folder.empty())
- {
- _Profile.StartingDirectory(folder);
- }
- }
-
- void Profiles::Pivot_SelectionChanged(Windows::Foundation::IInspectable const& /*sender*/,
- RoutedEventArgs const& /*e*/)
- {
- ProfileViewModel::LastActivePivot(static_cast(ProfilesPivot().SelectedIndex()));
- }
-}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.h b/src/cascadia/TerminalSettingsEditor/Profiles.h
index 6213bcbe69d..8b245b8fe28 100644
--- a/src/cascadia/TerminalSettingsEditor/Profiles.h
+++ b/src/cascadia/TerminalSettingsEditor/Profiles.h
@@ -3,7 +3,6 @@
#pragma once
-#include "Profiles.g.h"
#include "ProfilePageNavigationState.g.h"
#include "ProfileViewModel.h"
#include "Utils.h"
@@ -35,39 +34,4 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
};
-
- struct Profiles : public HasScrollViewer, ProfilesT
- {
- public:
- Profiles();
-
- void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
- void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
-
- fire_and_forget Commandline_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
- fire_and_forget StartingDirectory_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
- fire_and_forget Icon_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
- void DeleteConfirmation_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
- void Pivot_SelectionChanged(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
- void CreateUnfocusedAppearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
- void DeleteUnfocusedAppearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
-
- WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
-
- WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
-
- private:
- void _UpdateBIAlignmentControl(const int32_t val);
-
- std::array _BIAlignmentButtons;
- Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
- Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _AppearanceViewModelChangedRevoker;
-
- Microsoft::Terminal::Control::TermControl _previewControl;
- };
};
-
-namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
-{
- BASIC_FACTORY(Profiles);
-}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.idl b/src/cascadia/TerminalSettingsEditor/Profiles.idl
index 545579f2365..a3a1dafd1cf 100644
--- a/src/cascadia/TerminalSettingsEditor/Profiles.idl
+++ b/src/cascadia/TerminalSettingsEditor/Profiles.idl
@@ -10,12 +10,4 @@ namespace Microsoft.Terminal.Settings.Editor
{
ProfileViewModel Profile { get; };
};
-
- [default_interface] runtimeclass Profiles : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
- {
- Profiles();
- ProfileViewModel Profile { get; };
-
- Windows.UI.Xaml.Controls.Slider OpacitySlider { get; };
- }
}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.xaml b/src/cascadia/TerminalSettingsEditor/Profiles.xaml
deleted file mode 100644
index e1d3db94ec5..00000000000
--- a/src/cascadia/TerminalSettingsEditor/Profiles.xaml
+++ /dev/null
@@ -1,494 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.cpp b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.cpp
new file mode 100644
index 00000000000..79c0edffd76
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "Profiles_Advanced.h"
+#include "Profiles_Advanced.g.cpp"
+
+#include "EnumEntry.h"
+#include
+#include "..\WinRTUtils\inc\Utils.h"
+
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ Profiles_Advanced::Profiles_Advanced()
+ {
+ InitializeComponent();
+ }
+
+ void Profiles_Advanced::OnNavigatedTo(const NavigationEventArgs& e)
+ {
+ auto state{ e.Parameter().as() };
+ _Profile = state.Profile();
+ }
+
+ void Profiles_Advanced::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
+ {
+ _ViewModelChangedRevoker.revoke();
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.h b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.h
new file mode 100644
index 00000000000..1acd81d647a
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.h
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+#include "Profiles_Advanced.g.h"
+#include "ViewModelHelpers.h"
+#include "Utils.h"
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ struct Profiles_Advanced : public HasScrollViewer, Profiles_AdvancedT
+ {
+ public:
+ Profiles_Advanced();
+
+ void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
+ void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
+
+ WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
+ WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
+
+ private:
+ Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
+ };
+};
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
+{
+ BASIC_FACTORY(Profiles_Advanced);
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.idl b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.idl
new file mode 100644
index 00000000000..44a1cbca91a
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.idl
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import "Profiles.idl";
+
+namespace Microsoft.Terminal.Settings.Editor
+{
+ [default_interface] runtimeclass Profiles_Advanced : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
+ {
+ Profiles_Advanced();
+ ProfileViewModel Profile { get; };
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.xaml b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.xaml
new file mode 100644
index 00000000000..517cc3f9113
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Advanced.xaml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.cpp b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.cpp
new file mode 100644
index 00000000000..8ca25d19faa
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.cpp
@@ -0,0 +1,76 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "Profiles_Appearance.h"
+#include "Profiles_Appearance.g.cpp"
+#include "Profiles.h"
+#include "PreviewConnection.h"
+#include "EnumEntry.h"
+
+#include
+#include "..\WinRTUtils\inc\Utils.h"
+
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ Profiles_Appearance::Profiles_Appearance() :
+ _previewControl{ Control::TermControl(Model::TerminalSettings{}, nullptr, make()) }
+ {
+ InitializeComponent();
+
+ _previewControl.IsEnabled(false);
+ _previewControl.AllowFocusWhenDisabled(false);
+ ControlPreview().Child(_previewControl);
+ }
+
+ void Profiles_Appearance::OnNavigatedTo(const NavigationEventArgs& e)
+ {
+ auto state{ e.Parameter().as() };
+ _Profile = state.Profile();
+
+ // generate the font list, if we don't have one
+ if (_Profile.CompleteFontList() || !_Profile.MonospaceFontList())
+ {
+ ProfileViewModel::UpdateFontList();
+ }
+
+ // Subscribe to some changes in the view model
+ // These changes should force us to update our own set of "Current" members,
+ // and propagate those changes to the UI
+ _ViewModelChangedRevoker = _Profile.PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
+ _previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
+ });
+
+ // The Appearances object handles updating the values in the settings UI, but
+ // we still need to listen to the changes here just to update the preview control
+ _AppearanceViewModelChangedRevoker = _Profile.DefaultAppearance().PropertyChanged(winrt::auto_revoke, [=](auto&&, const PropertyChangedEventArgs& /*args*/) {
+ _previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
+ });
+
+ // There is a possibility that the control has not fully initialized yet,
+ // so wait for it to initialize before updating the settings (so we know
+ // that the renderer is set up)
+ _previewControl.Initialized([&](auto&& /*s*/, auto&& /*e*/) {
+ _previewControl.UpdateControlSettings(_Profile.TermSettings(), _Profile.TermSettings());
+ });
+ }
+
+ void Profiles_Appearance::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
+ {
+ _ViewModelChangedRevoker.revoke();
+ _AppearanceViewModelChangedRevoker.revoke();
+ }
+
+ void Profiles_Appearance::CreateUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
+ {
+ _Profile.CreateUnfocusedAppearance();
+ }
+
+ void Profiles_Appearance::DeleteUnfocusedAppearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
+ {
+ _Profile.DeleteUnfocusedAppearance();
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.h b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.h
new file mode 100644
index 00000000000..f85efca9c23
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.h
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+#include "Profiles_Appearance.g.h"
+#include "Utils.h"
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ struct Profiles_Appearance : public HasScrollViewer, Profiles_AppearanceT
+ {
+ public:
+ Profiles_Appearance();
+
+ void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
+ void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
+
+ void CreateUnfocusedAppearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void DeleteUnfocusedAppearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+
+ WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
+ WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
+
+ private:
+ Microsoft::Terminal::Control::TermControl _previewControl;
+ Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
+ Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _AppearanceViewModelChangedRevoker;
+ };
+};
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
+{
+ BASIC_FACTORY(Profiles_Appearance);
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.idl b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.idl
new file mode 100644
index 00000000000..dff812912a7
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.idl
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import "Profiles.idl";
+
+namespace Microsoft.Terminal.Settings.Editor
+{
+ [default_interface] runtimeclass Profiles_Appearance : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
+ {
+ Profiles_Appearance();
+ ProfileViewModel Profile { get; };
+
+ Windows.UI.Xaml.Controls.Slider OpacitySlider { get; };
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.xaml b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.xaml
new file mode 100644
index 00000000000..a506c1e80cc
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.xaml
@@ -0,0 +1,230 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Base.cpp b/src/cascadia/TerminalSettingsEditor/Profiles_Base.cpp
new file mode 100644
index 00000000000..1c75efabfc9
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Base.cpp
@@ -0,0 +1,128 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "Profiles_Base.h"
+#include "Profiles_Base.g.cpp"
+#include "Profiles.h"
+
+#include
+#include "..\WinRTUtils\inc\Utils.h"
+
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ Profiles_Base::Profiles_Base()
+ {
+ InitializeComponent();
+
+ const auto startingDirCheckboxTooltip{ ToolTipService::GetToolTip(StartingDirectoryUseParentCheckbox()) };
+ Automation::AutomationProperties::SetFullDescription(StartingDirectoryUseParentCheckbox(), unbox_value(startingDirCheckboxTooltip));
+
+ Automation::AutomationProperties::SetName(DeleteButton(), RS_(L"Profile_DeleteButton/Text"));
+ AppearanceNavigator().Content(box_value(RS_(L"Profile_Appearance/Header")));
+ AdvancedNavigator().Content(box_value(RS_(L"Profile_Advanced/Header")));
+ }
+
+ void Profiles_Base::OnNavigatedTo(const NavigationEventArgs& e)
+ {
+ auto state{ e.Parameter().as() };
+ _Profile = state.Profile();
+
+ // Check the use parent directory box if the starting directory is empty
+ if (_Profile.StartingDirectory().empty())
+ {
+ StartingDirectoryUseParentCheckbox().IsChecked(true);
+ }
+ }
+
+ void Profiles_Base::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
+ {
+ _ViewModelChangedRevoker.revoke();
+ }
+
+ void Profiles_Base::Appearance_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*args*/)
+ {
+ _Profile.CurrentPage(ProfileSubPage::Appearance);
+ }
+
+ void Profiles_Base::Advanced_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*args*/)
+ {
+ _Profile.CurrentPage(ProfileSubPage::Advanced);
+ }
+
+ void Profiles_Base::DeleteConfirmation_Click(IInspectable const& /*sender*/, RoutedEventArgs const& /*e*/)
+ {
+ winrt::get_self(_Profile)->DeleteProfile();
+ }
+
+ fire_and_forget Profiles_Base::Commandline_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ static constexpr COMDLG_FILTERSPEC supportedFileTypes[] = {
+ { L"Executable Files (*.exe, *.cmd, *.bat)", L"*.exe;*.cmd;*.bat" },
+ { L"All Files (*.*)", L"*.*" }
+ };
+
+ static constexpr winrt::guid clientGuidExecutables{ 0x2E7E4331, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
+ const auto parentHwnd{ reinterpret_cast(winrt::get_self(_Profile)->WindowRoot().GetHostingWindow()) };
+ auto path = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
+ THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExecutables));
+ try
+ {
+ auto folderShellItem{ winrt::capture(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
+ dialog->SetDefaultFolder(folderShellItem.get());
+ }
+ CATCH_LOG(); // non-fatal
+ THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
+ THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
+ THROW_IF_FAILED(dialog->SetDefaultExtension(L"exe;cmd;bat"));
+ });
+
+ if (!path.empty())
+ {
+ _Profile.Commandline(path);
+ }
+ }
+
+ fire_and_forget Profiles_Base::Icon_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ const auto parentHwnd{ reinterpret_cast(winrt::get_self(_Profile)->WindowRoot().GetHostingWindow()) };
+ auto file = co_await OpenImagePicker(parentHwnd);
+ if (!file.empty())
+ {
+ _Profile.Icon(file);
+ }
+ }
+
+ fire_and_forget Profiles_Base::StartingDirectory_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+ const auto parentHwnd{ reinterpret_cast(winrt::get_self(_Profile)->WindowRoot().GetHostingWindow()) };
+ auto folder = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
+ static constexpr winrt::guid clientGuidFolderPicker{ 0xAADAA433, 0xB04D, 0x4BAE, { 0xB1, 0xEA, 0x1E, 0x6C, 0xD1, 0xCD, 0xA6, 0x8B } };
+ THROW_IF_FAILED(dialog->SetClientGuid(clientGuidFolderPicker));
+ try
+ {
+ auto folderShellItem{ winrt::capture(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
+ dialog->SetDefaultFolder(folderShellItem.get());
+ }
+ CATCH_LOG(); // non-fatal
+
+ DWORD flags{};
+ THROW_IF_FAILED(dialog->GetOptions(&flags));
+ THROW_IF_FAILED(dialog->SetOptions(flags | FOS_PICKFOLDERS)); // folders only
+ });
+
+ if (!folder.empty())
+ {
+ _Profile.StartingDirectory(folder);
+ }
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Base.h b/src/cascadia/TerminalSettingsEditor/Profiles_Base.h
new file mode 100644
index 00000000000..778a2f675cc
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Base.h
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+#include "Profiles_Base.g.h"
+#include "ViewModelHelpers.h"
+#include "Utils.h"
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ struct Profiles_Base : public HasScrollViewer, Profiles_BaseT
+ {
+ public:
+ Profiles_Base();
+
+ void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
+ void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
+
+ fire_and_forget StartingDirectory_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ fire_and_forget Icon_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ fire_and_forget Commandline_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void Appearance_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void Advanced_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void DeleteConfirmation_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+
+ WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
+ WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);
+
+ private:
+ Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
+ };
+};
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
+{
+ BASIC_FACTORY(Profiles_Base);
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Base.idl b/src/cascadia/TerminalSettingsEditor/Profiles_Base.idl
new file mode 100644
index 00000000000..a0cd1b88aba
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Base.idl
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+import "Profiles.idl";
+
+namespace Microsoft.Terminal.Settings.Editor
+{
+ [default_interface] runtimeclass Profiles_Base : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
+ {
+ Profiles_Base();
+ ProfileViewModel Profile { get; };
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Base.xaml b/src/cascadia/TerminalSettingsEditor/Profiles_Base.xaml
new file mode 100644
index 00000000000..4f593012110
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/Profiles_Base.xaml
@@ -0,0 +1,242 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Appearance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/Rendering.xaml b/src/cascadia/TerminalSettingsEditor/Rendering.xaml
index 3746a444c5e..72f39027bca 100644
--- a/src/cascadia/TerminalSettingsEditor/Rendering.xaml
+++ b/src/cascadia/TerminalSettingsEditor/Rendering.xaml
@@ -25,12 +25,14 @@
-
+
-
+
diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
index 25af7bfbe4c..a069c7de6ec 100644
--- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
@@ -279,22 +279,14 @@
When disabled, the terminal will render only the updates to the screen between frames.A description for what the "force full repaint" setting does. Presented near "Globals_ForceFullRepaint.Header".
-
+
ColumnsHeader for a control to choose the number of columns in the terminal's text grid.
-
- The number of columns displayed in the window upon first load. Measured in characters.
- A description for what the "columns" setting does. Presented near "Globals_InitialCols.Header".
-
-
+
RowsHeader for a control to choose the number of rows in the terminal's text grid.
-
- The number of rows displayed in the window upon first load. Measured in characters.
- A description for what the "rows" setting does. Presented near "Globals_InitialRows.Header".
-
Initial ColumnsName for a control to choose the number of columns in the terminal's text grid.
@@ -372,19 +364,19 @@
A description for what the "show titlebar" setting does. Presented near "Globals_ShowTitlebar.Header".
- Show acrylic in tab row (requires relaunch)
- Header for a control to toggle whether acrylic shows in the tab row. Changing this setting requires the user to relaunch the app.
+ Use acrylic material in the tab row (requires relaunch)
+ Header for a control to toggle whether "acrylic material" is used. "Acrylic material" is a Microsoft-specific term: https://docs.microsoft.com/en-us/windows/apps/design/style/acrylicWhen checked, the tab row will have the acrylic material.
- A description for what the "use acrylic in tab row" setting does. Presented near "Globals_AcrylicTabRow.Header".
+ A description for the "Globals_AcrylicTabRow.Header" setting does. "Acrylic material" is a Microsoft-specific term: https://docs.microsoft.com/en-us/windows/apps/design/style/acrylicUse active terminal title as application titleHeader for a control to toggle whether the terminal's title is shown as the application title, or not.
- When disabled, the title bar will be 'Windows Terminal'.
+ When disabled, the title bar will be 'Terminal'.A description for what the "show title in titlebar" setting does. Presented near "Globals_ShowTitleInTitlebar.Header".{Locked="Windows"}
@@ -408,7 +400,7 @@
Header for a control to toggle whether the app should launch when the user's machine starts up, or not.
- When enabled, this enables the launch of Windows Terminal at machine startup.
+ When enabled, this enables the launch of Terminal at machine startup.A description for what the "start on user login" setting does. Presented near "Globals_StartOnUserLogin.Header".
@@ -416,7 +408,7 @@
Header for a control to toggle if the app will always be presented on top of other windows, or is treated normally (when disabled).
- Windows Terminal will always be the topmost window on the desktop.
+ Terminal will always be the topmost window on the desktop.A description for what the "always on top" setting does. Presented near "Globals_AlwaysOnTop.Header".
@@ -471,18 +463,34 @@
AppearanceHeader for the "appearance" menu item. This navigates to a page that lets you see and modify settings related to the app's appearance.
+
+ Appearance
+ Tooltip for the "appearance" menu item.
+
Color schemesHeader for the "color schemes" menu item. This navigates to a page that lets you see and modify schemes of colors that can be used by the terminal.
+
+ Color schemes
+ Tooltip for the "color schemes" menu item.
+
InteractionHeader for the "interaction" menu item. This navigates to a page that lets you see and modify settings related to the user's mouse and touch interactions with the app.
+
+ Interaction
+ Tooltip for the "interaction" menu item.
+
StartupHeader for the "startup" menu item. This navigates to a page that lets you see and modify settings related to the app's launch experience (i.e. screen position, mode, etc.)
+
+ Startup
+ Tooltip for the "startup" menu item.
+
Open JSON fileHeader for a menu item. This opens the JSON file that is used to log the app's settings.
@@ -491,21 +499,29 @@
DefaultsHeader for the "defaults" menu item. This navigates to a page that lets you see and modify settings that affect profiles. This is the lowest layer of profile settings that all other profile settings are based on. If a profile doesn't define a setting, this page is responsible for figuring out what that setting is supposed to be.
+
+ Defaults
+ Tooltip for the "profile defaults" menu item.
+
RenderingHeader for the "rendering" menu item. This navigates to a page that lets you see and modify settings related to the app's rendering of text in the terminal.
+
+ Rendering
+ Tooltip for the "rendering" menu item.
+
ActionsHeader for the "actions" menu item. This navigates to a page that lets you see and modify commands, key bindings, and actions that can be done in the app.
-
- Acrylic opacity
- Header for a control to determine the level of opacity for the acrylic rendering material. The user can choose to make the acrylic background of the app more or less opaque.
+
+ Actions
+ Tooltip for the "actions" menu item.
-
- Sets the transparency of the window.
- A description for what the "acrylic opacity" setting does. Presented near "Profile_AcrylicOpacity.Header".
+
+ Background opacity
+ Name for a control to determine the level of opacity for the background of the control. The user can choose to make the background of the app more or less opaque.Background opacity
@@ -527,6 +543,10 @@
By default Windows treats Ctrl+Alt as an alias for AltGr. When disabled, this behavior will be disabled.A description for what the "AltGr aliasing" setting does. Presented near "Profile_AltGrAliasing.Header".
+
+ Text antialiasing
+ Name for a control to select the graphical anti-aliasing format of text.
+
Text antialiasingHeader for a control to select the graphical anti-aliasing format of text.
@@ -551,6 +571,14 @@
AppearanceHeader for a sub-page of profile settings focused on customizing the appearance of the profile.
+
+ Background image path
+ Name for a control to determine the image presented on the background of the app.
+
+
+ Background image path
+ Name for a control to determine the image presented on the background of the app.
+
Background image pathHeader for a control to determine the image presented on the background of the app.
@@ -559,6 +587,10 @@
File location of the image used in the background of the window.A description for what the "background image path" setting does. Presented near "Profile_BackgroundImage".
+
+ Background image alignment
+ Name for a control to choose the visual alignment of the image presented on the background of the app.
+
Background image alignmentHeader for a control to choose the visual alignment of the image presented on the background of the app.
@@ -607,6 +639,10 @@
Browse...Button label that opens a file picker in a new window. The "..." is standard to mean it will open a new window.
+
+ Background image opacity
+ Name for a control to choose the opacity of the image presented on the background of the app.
+
Background image opacityHeader for a control to choose the opacity of the image presented on the background of the app.
@@ -615,6 +651,10 @@
Sets the transparency of the background image.A description for what the "background image opacity" setting does. Presented near "Profile_BackgroundImageOpacity".
+
+ Background image stretch mode
+ Name for a control to choose the stretch mode of the image presented on the background of the app. Stretch mode is how the image is resized to fill its allocated space.
+
Background image stretch modeHeader for a control to choose the stretch mode of the image presented on the background of the app. Stretch mode is how the image is resized to fill its allocated space.
@@ -639,6 +679,10 @@
Uniform to fillAn option to choose from for the "background image stretch mode" setting. When selected, the content is resized to fill the destination dimensions while it preserves its native aspect ratio. But if the aspect ratio of the destination differs, the image is clipped to fit in the space (to fill the space)
+
+ Profile termination behavior
+ Name for a control to select the behavior of a terminal session (a profile) when it closes.
+
Profile termination behaviorHeader for a control to select the behavior of a terminal session (a profile) when it closes.
@@ -663,6 +707,10 @@
Name of the color scheme to use.A description for what the "color scheme" setting does. Presented near "Profile_ColorScheme".
+
+ Command line
+ Name for a control to determine commandline executable (i.e. a .exe file) to run when a terminal session of this profile is launched.
+
Command lineHeader for a control to determine commandline executable (i.e. a .exe file) to run when a terminal session of this profile is launched.
@@ -687,6 +735,10 @@
Sets the percentage height of the cursor starting from the bottom. Only works with the vintage cursor shape.A description for what the "cursor height" setting does. Presented near "Profile_CursorHeight".
+
+ Cursor shape
+ Name for a control to select the shape of the text cursor.
+
Cursor shapeHeader for a control to select the shape of the text cursor.
@@ -739,6 +791,14 @@
Size of the font in points.A description for what the "font size" setting does. Presented near "Profile_FontSize".
+
+ Font weight
+ Name for a control to select the weight (i.e. bold, thin, etc.) of the text in the app.
+
+
+ Font weight
+ Name for a control to select the weight (i.e. bold, thin, etc.) of the text in the app.
+
Font weightHeader for a control to select the weight (i.e. bold, thin, etc.) of the text in the app.
@@ -759,6 +819,14 @@
If enabled, the profile will not appear in the list of profiles. This can be used to hide default profiles and dynamically generated profiles, while leaving them in your settings file.A description for what the "hidden" setting does. Presented near "Profile_Hidden".
+
+ Run this profile as Administrator
+ Header for a control to toggle whether the profile should always open elevated (in an admin window)
+
+
+ If enabled, the profile will open in an Admin terminal window automatically. If the current window is already running as admin, it'll open in this window.
+ A description for what the "elevate" setting does. Presented near "Profile_Elevate".
+
History sizeHeader for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session.
@@ -771,6 +839,10 @@
The number of lines above the ones displayed in the window you can scroll back to.A description for what the "history size" setting does. Presented near "Profile_HistorySize".
+
+ Icon
+ Name for a control to determine what icon can be used to represent this profile. This is not necessarily a file path, but can be one.
+
IconHeader for a control to determine what icon can be used to represent this profile. This is not necessarily a file path, but can be one.
@@ -787,6 +859,10 @@
Browse...Button label that opens a file picker in a new window. The "..." is standard to mean it will open a new window.
+
+ Padding
+ Name for a control to determine the amount of space between text in a terminal and the edge of the window.
+
PaddingHeader for a control to determine the amount of space between text in a terminal and the edge of the window. The space can be any combination of the top, bottom, left, and right side of the window.
@@ -811,6 +887,10 @@
When enabled, enables automatic adjustment of indistinguishable colors, which will, only when necessary, adjust the foreground color's lightness to make it more visible (based on the background color).A description for what the "adjust indistinguishable colors" setting does. Presented near "Profile_AdjustIndistinguishableColors".
+
+ Scrollbar visibility
+ Name for a control to select the visibility of the scrollbar in a session.
+
Scrollbar visibilityHeader for a control to select the visibility of the scrollbar in a session.
@@ -827,6 +907,10 @@
Scroll to input when typingHeader for a control to toggle if keyboard input should automatically scroll to where the input was placed.
+
+ Starting directory
+ Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.
+
Starting directoryHeader for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.
@@ -848,7 +932,7 @@
A supplementary setting to the "starting directory" setting. "Parent" refers to the parent process of the current process.
- If enabled, this profile will spawn in the directory from which Windows Terminal was launched.
+ If enabled, this profile will spawn in the directory from which Terminal was launched.A description for what the supplementary "use parent process directory" setting does. Presented near "Profile_StartingDirectoryUseParentCheckbox".
@@ -859,6 +943,10 @@
Use the tab title to override the default title of the tab and suppress any title change messages from the application.A description for what the "suppress application title" setting does. Presented near "Profile_SuppressApplicationTitle".
+
+ Tab title
+ Name for a control to determine the title of the tab. This is represented using a text box.
+
Tab titleHeader for a control to determine the title of the tab. This is represented using a text box.
@@ -868,16 +956,24 @@
A description for what the "tab title" setting does. Presented near "Profile_TabTitle".
- Unfocused Appearance
+ Unfocused appearanceThe header for the section where the unfocused appearance settings can be changed.
+
+ Add
+ Button label that adds an unfocused appearance for this profile.
+
+
+ Delete
+ Button label that deletes the unfocused appearance for this profile.
+
- Enable acrylic
- Header for a control to toggle the acrylic-like rendering of the background. The acrylic material creates a translucent texture.
+ Enable acrylic material
+ Header for a control to toggle the use of acrylic material for the background. "Acrylic material" is a Microsoft-specific term: https://docs.microsoft.com/en-us/windows/apps/design/style/acrylicApplies a translucent texture to the background of the window.
- A description for what the "enable acrylic" setting does. Presented near "Profile_UseAcrylic".
+ A description for what the "Profile_UseAcrylic" setting does.Use desktop wallpaper
@@ -931,6 +1027,10 @@
Maximized full screen focusAn option to choose from for the "launch mode" setting. Opens the app maximized in full screen and in focus mode.
+
+ Bell notification style
+ Name for a control to select the how the app notifies the user. "Bell" is the common term in terminals for the BEL character (like the metal device used to chime).
+
Bell notification styleHeader for a control to select the how the app notifies the user. "Bell" is the common term in terminals for the BEL character (like the metal device used to chime).
@@ -1003,10 +1103,14 @@
ThinThis is the formal name for a font weight.
-
+
Launch sizeHeader for a group of settings that control the size of the app. Presented near "Globals_InitialCols" and "Globals_InitialRows".
+
+ The number of rows and columns displayed in the window upon first load. Measured in characters.
+ A description for what the "rows" and "columns" settings do. Presented near "Globals_LaunchSize.Header".
+
AllAn option to choose from for the "bell style" setting. When selected, a combination of the other bell styles is used to notify the user.
@@ -1046,17 +1150,17 @@
The name of the profile that appears in the dropdown.A description for what the "name" setting does. Presented near "Profile_Name".
+
+ Name
+ Name for a control to determine the name of the profile. This is a text box.
+
NameHeader for a control to determine the name of the profile. This is a text box.
-
- Acrylic
- Header for a group of settings related to the acrylic texture rendering on the background of the app.
-
Transparency
- Header for a group of settings related to transparency, including the acrylic texture rendering on the background of the app.
+ Header for a group of settings related to transparency, including the acrylic material background of the app.Background image
@@ -1066,6 +1170,10 @@
CursorHeader for a group of settings that control the appearance of the cursor. Presented near "Profile_CursorHeight" and other keys starting with "Profile_Cursor".
+
+ Additional settings
+ Header for the buttons that navigate to additional settings for the profile.
+
TextHeader for a group of settings that control the appearance of text in the app.
@@ -1210,10 +1318,18 @@
If enabled, show all installed fonts in the list above. Otherwise, only show the list of monospace fonts.A description for what the supplementary "show all fonts" setting does. Presented near "Profile_FontFaceShowAllFonts".
+
+ Create Appearance
+ Name for a control which creates an the unfocused appearance settings for this profile.
+
Create an unfocused appearance for this profile. This will be the appearance of the profile when it is inactive.A description for what the create unfocused appearance button does.
+
+ Delete Appearance
+ Name for a control which deletes an the unfocused appearance settings for this profile.
+
Delete the unfocused appearance for this profile.A description for what the delete unfocused appearance button does.
@@ -1286,6 +1402,10 @@
Text FormattingHeader for a control to how text is formatted
+
+ Intense text style
+ Name for a control to select how "intense" text is formatted (bold, bright, both or none)
+
Intense text styleHeader for a control to select how "intense" text is formatted (bold, bright, both or none)
diff --git a/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp b/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp
index 4403827834c..3d1e55c1e83 100644
--- a/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp
+++ b/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp
@@ -12,6 +12,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
DependencyProperty SettingContainer::_HeaderProperty{ nullptr };
DependencyProperty SettingContainer::_HelpTextProperty{ nullptr };
+ DependencyProperty SettingContainer::_CurrentValueProperty{ nullptr };
DependencyProperty SettingContainer::_HasSettingValueProperty{ nullptr };
DependencyProperty SettingContainer::_SettingOverrideSourceProperty{ nullptr };
@@ -43,6 +44,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
xaml_typename(),
PropertyMetadata{ box_value(L"") });
}
+ if (!_CurrentValueProperty)
+ {
+ _CurrentValueProperty =
+ DependencyProperty::Register(
+ L"CurrentValue",
+ xaml_typename(),
+ xaml_typename(),
+ PropertyMetadata{ box_value(L"") });
+ }
if (!_HasSettingValueProperty)
{
_HasSettingValueProperty =
@@ -135,6 +145,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
}
}
+
+ if (HelpText().empty())
+ {
+ if (const auto& child{ GetTemplateChild(L"HelpTextBlock") })
+ {
+ if (const auto& textBlock{ child.try_as() })
+ {
+ textBlock.Visibility(Visibility::Collapsed);
+ }
+ }
+ }
}
// Method Description:
diff --git a/src/cascadia/TerminalSettingsEditor/SettingContainer.h b/src/cascadia/TerminalSettingsEditor/SettingContainer.h
index de9570e7f11..7accd8735b9 100644
--- a/src/cascadia/TerminalSettingsEditor/SettingContainer.h
+++ b/src/cascadia/TerminalSettingsEditor/SettingContainer.h
@@ -31,6 +31,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
DEPENDENCY_PROPERTY(Windows::Foundation::IInspectable, Header);
DEPENDENCY_PROPERTY(hstring, HelpText);
+ DEPENDENCY_PROPERTY(hstring, CurrentValue);
DEPENDENCY_PROPERTY(bool, HasSettingValue);
DEPENDENCY_PROPERTY(IInspectable, SettingOverrideSource);
TYPED_EVENT(ClearSettingValue, Editor::SettingContainer, Windows::Foundation::IInspectable);
diff --git a/src/cascadia/TerminalSettingsEditor/SettingContainer.idl b/src/cascadia/TerminalSettingsEditor/SettingContainer.idl
index 3c75cd2dc33..39638ca4fe8 100644
--- a/src/cascadia/TerminalSettingsEditor/SettingContainer.idl
+++ b/src/cascadia/TerminalSettingsEditor/SettingContainer.idl
@@ -13,6 +13,9 @@ namespace Microsoft.Terminal.Settings.Editor
String HelpText;
static Windows.UI.Xaml.DependencyProperty HelpTextProperty { get; };
+ String CurrentValue;
+ static Windows.UI.Xaml.DependencyProperty CurrentValueProperty { get; };
+
Boolean HasSettingValue;
static Windows.UI.Xaml.DependencyProperty HasSettingValueProperty { get; };
diff --git a/src/cascadia/TerminalSettingsEditor/SettingContainerStyle.xaml b/src/cascadia/TerminalSettingsEditor/SettingContainerStyle.xaml
index 717e6e80855..5efb9a2ebb6 100644
--- a/src/cascadia/TerminalSettingsEditor/SettingContainerStyle.xaml
+++ b/src/cascadia/TerminalSettingsEditor/SettingContainerStyle.xaml
@@ -7,12 +7,51 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
-
+
+ #0F000000
+
+
+
+
+
+
+
+
+
+
+
+
+ #19000000
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+