mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-19 03:10:49 +00:00
Compare commits
37 Commits
dev/cazamo
...
v1.25.1241
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
168dc99a6a | ||
|
|
e9f8ec877b | ||
|
|
021a571dfb | ||
|
|
ed6cb17ecb | ||
|
|
b2d88cbe42 | ||
|
|
fcc614e9f5 | ||
|
|
5af583ef5a | ||
|
|
82dfa63202 | ||
|
|
418401e1c2 | ||
|
|
88a236c913 | ||
|
|
0252c78997 | ||
|
|
82d5e0cad3 | ||
|
|
d960f4a05a | ||
|
|
2c9277cbb4 | ||
|
|
e382d328b2 | ||
|
|
2bd369939c | ||
|
|
7f5185eb06 | ||
|
|
0291d97503 | ||
|
|
f7a5515cf7 | ||
|
|
2219739391 | ||
|
|
7cff119b34 | ||
|
|
58414c542f | ||
|
|
bf77086b60 | ||
|
|
2644ca0a8a | ||
|
|
1ad9a2e932 | ||
|
|
74f3bb42e1 | ||
|
|
c0ca78c3ee | ||
|
|
37dc437e65 | ||
|
|
4a782b062c | ||
|
|
4701843082 | ||
|
|
efe9f27c00 | ||
|
|
008e293205 | ||
|
|
7adb2157a5 | ||
|
|
9ae724aa5b | ||
|
|
d6da2555f5 | ||
|
|
f740350283 | ||
|
|
62512eb116 |
8
.github/workflows/spelling2.yml
vendored
8
.github/workflows/spelling2.yml
vendored
@@ -93,7 +93,7 @@ jobs:
|
||||
steps:
|
||||
- name: check-spelling
|
||||
id: spelling
|
||||
uses: check-spelling/check-spelling@c635c2f3f714eec2fcf27b643a1919b9a811ef2e # v0.0.25
|
||||
uses: check-spelling/check-spelling@v0.0.25
|
||||
with:
|
||||
suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }}
|
||||
checkout: true
|
||||
@@ -153,7 +153,7 @@ jobs:
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push'
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@c635c2f3f714eec2fcf27b643a1919b9a811ef2e # v0.0.25
|
||||
uses: check-spelling/check-spelling@v0.0.25
|
||||
with:
|
||||
checkout: true
|
||||
spell_check_this: microsoft/terminal@main
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
|
||||
steps:
|
||||
- name: comment
|
||||
uses: check-spelling/check-spelling@c635c2f3f714eec2fcf27b643a1919b9a811ef2e # v0.0.25
|
||||
uses: check-spelling/check-spelling@v0.0.25
|
||||
with:
|
||||
checkout: true
|
||||
spell_check_this: microsoft/terminal@main
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
cancel-in-progress: false
|
||||
steps:
|
||||
- name: apply spelling updates
|
||||
uses: check-spelling/check-spelling@c635c2f3f714eec2fcf27b643a1919b9a811ef2e # v0.0.25
|
||||
uses: check-spelling/check-spelling@v0.0.25
|
||||
with:
|
||||
experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }}
|
||||
checkout: true
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
- [Via Chocolatey (unofficial)](#via-chocolatey-unofficial)
|
||||
- [Via Scoop (unofficial)](#via-scoop-unofficial)
|
||||
- [Installing Windows Terminal Canary](#installing-windows-terminal-canary)
|
||||
- [Windows Terminal Roadmap](#windows-terminal-roadmap)
|
||||
- [Terminal \& Console Overview](#terminal--console-overview)
|
||||
- [Windows Terminal](#windows-terminal)
|
||||
- [The Windows Console Host](#the-windows-console-host)
|
||||
@@ -177,6 +178,11 @@ _Learn more about the [types of Windows Terminal distributions](https://learn.mi
|
||||
|
||||
---
|
||||
|
||||
## Windows Terminal Roadmap
|
||||
|
||||
The plan for the Windows Terminal [is described here](/doc/roadmap-2023.md) and
|
||||
will be updated as the project proceeds.
|
||||
|
||||
## Terminal & Console Overview
|
||||
|
||||
Please take a few minutes to review the overview below before diving into the
|
||||
|
||||
@@ -56,10 +56,9 @@ Dies ist ein Open Source-Projekt, und wir freuen uns über die Teilnahme der Com
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
– Endlich die Möglichkeit, nach beliebigen Einstellungen zu suchen!
|
||||
– Ein neuer nativer Editor für Tastenkombinationen, Aktionen und Einträge in der Befehlspalette.
|
||||
– Neue Community-Übersetzungen für Serbisch und Ukrainisch
|
||||
– Unterstützung für das „Kitty“-Tastaturprotokoll für hochauflösende Eingabecodierung
|
||||
– Eine komplett neue Erweiterungsseite, die anzeigt, was in Ihrem Terminal installiert ist
|
||||
– Die Befehlspalette wird jetzt sowohl in Ihrer Muttersprache als auch auf Englisch angezeigt
|
||||
– Neue VT-Features wie synchronisiertes Rendering, neue Farbschemas, Konfiguration für schnelle Mausaktionen wie Zoomen und mehr
|
||||
|
||||
Weitere Informationen finden Sie auf unserer GitHub-Releaseseite.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -54,12 +54,11 @@ This is an open source project and we welcome community participation. To partic
|
||||
<!-- _locComment_text="{MaxLength=255} App DevStudio" -->
|
||||
</DevStudio>
|
||||
<ReleaseNotes _locID="App_ReleaseNotes">
|
||||
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe}{Locked=Kitty} App Release Note" -->Version __VERSION_NUMBER__
|
||||
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe} App Release Note" -->Version __VERSION_NUMBER__
|
||||
|
||||
- Finally, the ability to search for any setting!
|
||||
- A new native editor for key bindings, actions and command palette entries.
|
||||
- New community localizations to Serbian and Ukrainian
|
||||
- Support for the "Kitty" keyboard protocol for high-fidelity input encoding
|
||||
- A whole new Extensions page that shows what has been installed into your Terminal
|
||||
- Command Palette now shows up in your native language as well as English
|
||||
- New VT features such as synchronized rendering, new color schemes, configuration for quick mouse actions like zooming, and more
|
||||
|
||||
Please see our GitHub releases page for additional details.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -54,12 +54,11 @@ Este es un proyecto de fuente abierta y animamos a la comunidad a participar. Pa
|
||||
|
||||
</DevStudio>
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
Versión __VERSION_NUMBER__
|
||||
|
||||
- Por último, la capacidad de buscar cualquier configuración.
|
||||
- Nuevo editor nativo para asignaciones de teclas, acciones y entradas de la paleta de comandos.
|
||||
- Nuevas localizaciones comunitarias para serbio y ucraniano
|
||||
- Soporte para el protocolo de teclado "Kitty" para codificación de entrada de alta fidelidad
|
||||
- Página Extensiones completamente nueva que muestra lo que se ha instalado en tu terminal
|
||||
- La paleta de comandos ahora se muestra en tu idioma nativo, así como en inglés
|
||||
- Nuevas características de VT, como la representación sincronizada, nuevos esquemas de color, configuración para acciones rápidas del ratón, como el zoom, y más
|
||||
|
||||
Consulta la página de versiones de GitHub para más información.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,12 +56,11 @@ Il s’agit d’un projet open source et nous vous invitons à participer dans l
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
- Enfin, la possibilité de rechercher n’importe quel paramètre !
|
||||
- Un nouvel éditeur natif pour les raccourcis clavier, les actions et les entrées de la palette de commandes.
|
||||
- De nouvelles localisations communautaires en serbe et en ukrainien
|
||||
- Une prise en charge du protocole clavier « Kitty » pour un encodage d’entrée à haute fidélité
|
||||
- Une toute nouvelle page Extensions qui montre ce qui a été installé dans votre terminal
|
||||
- La palette de commandes s’affiche désormais dans votre langue native, ainsi qu’en anglais
|
||||
- Nouvelles fonctionnalités VT telles que le rendu synchronisé, de nouveaux schémas de couleurs, la configuration pour des actions rapides de la souris comme le zoom, et plus encore
|
||||
|
||||
Consultez notre page des versions de GitHub pour plus de détails.
|
||||
Veuillez consulter notre page des versions GitHub pour découvrir d’autres détails.
|
||||
</ReleaseNotes>
|
||||
<ScreenshotCaptions>
|
||||
<!-- Valid length: 200 character limit, up to 9 elements per platform -->
|
||||
|
||||
@@ -54,12 +54,11 @@ Si tratta di un progetto open source e la partecipazione della community è molt
|
||||
|
||||
</DevStudio>
|
||||
<ReleaseNotes>
|
||||
Versione __VERSION_NUMBER__
|
||||
Versione __VERSION_NUMBER__
|
||||
|
||||
- Finalmente è possibile cercare qualsiasi impostazione
|
||||
- Nuovo editor nativo per le associazioni di tasti, le azioni e le voci del riquadro comandi.
|
||||
- Nuove localizzazioni della community in serbo e ucraino
|
||||
- Supporto per il protocollo di tastiera "Kitty" per una codifica dell'input ad alta fedeltà
|
||||
- Una pagina Estensioni completamente nuova che mostra ciò che è stato installato nel terminale
|
||||
- Il riquadro comandi ora viene visualizzato nella tua lingua di origine oltre che in inglese
|
||||
- Nuove funzionalità VT come il rendering sincronizzato, le nuove combinazioni di colori, la configurazione per azioni rapide del mouse come lo zoom e altro ancora
|
||||
|
||||
Per altri dettagli, vedi la pagina delle release di GitHub.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,10 +56,9 @@
|
||||
<ReleaseNotes>
|
||||
バージョン __VERSION_NUMBER__
|
||||
|
||||
- 最後に、任意の設定を検索する機能です。
|
||||
- キー バインド、アクション、コマンド パレット エントリ用の新しいネイティブ エディター。
|
||||
- セルビア語とウクライナ語への新しいコミュニティ ローカライズ
|
||||
- 高忠実度入力エンコード用の "Kitty" キーボード プロトコルのサポート
|
||||
- ターミナルに何がインストールされているかを表示する新しい [拡張機能] ページ
|
||||
- コマンド パレットがネイティブ言語と英語で表示されるようになりました
|
||||
- 同期レンダリング、新しい配色、ズームなどのクイック マウス操作の構成などの、新しい VT 機能
|
||||
|
||||
詳細については、GitHub リリース ページをご覧ください。
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,12 +56,11 @@
|
||||
<ReleaseNotes>
|
||||
버전 __VERSION_NUMBER__
|
||||
|
||||
- 드디어 모든 설정을 검색할 수 있게 되었어요!
|
||||
- 키 바인딩, 작업, 명령 팔레트 항목을 위한 새로운 기본 편집기가 추가되었습니다.
|
||||
- 세르비아어와 우크라이나어 커뮤니티 지역화를 새롭게 지원합니다.
|
||||
- 고품질 입력 인코딩을 위해 "Kitty" 키보드 프로토콜을 지원합니다.
|
||||
- 터미널에 설치된 항목을 보여 주는 완전히 새로운 확장 페이지
|
||||
- 명령 팔레트가 이제 영어뿐만 아니라 모국어로도 표시
|
||||
- 동기화된 렌더링, 새로운 색 구성표, 확대/축소와 같은 빠른 마우스 동작을 위한 구성 등 새로운 VT 기능이 추가
|
||||
|
||||
자세한 정보는 GitHub 릴리스 페이지를 참고하세요.
|
||||
자세한 내용은 GitHub 릴리스 페이지를 참조하세요.
|
||||
</ReleaseNotes>
|
||||
<ScreenshotCaptions>
|
||||
<!-- Valid length: 200 character limit, up to 9 elements per platform -->
|
||||
|
||||
@@ -56,10 +56,9 @@ Este é um projeto de código aberto e a participação da comunidade é bem-vin
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
- Finalmente, a possibilidade de pesquisar qualquer configuração!
|
||||
- Um novo editor nativo para combinações de teclas, ações e entradas na paleta de comandos.
|
||||
- Novas localizações da comunidade para sérvio e ucraniano
|
||||
- Suporte para o protocolo de teclado "Kitty" para codificação de entrada de alta fidelidade
|
||||
– Uma nova página de Extensões que mostra o que foi instalado no seu Terminal
|
||||
– A Paleta de Comandos agora aparece no seu idioma nativo, além do inglês
|
||||
– Novos recursos da VT, como renderização sincronizada, novos esquemas de cores, configuração para ações rápidas do mouse, como zoom, e muito mais
|
||||
|
||||
Confira nossa página de lançamentos no GitHub para obter mais detalhes.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,10 +56,9 @@
|
||||
<ReleaseNotes>
|
||||
Версия __VERSION_NUMBER__
|
||||
|
||||
– Наконец-то появилась возможность поиска любых параметров!
|
||||
– Новый собственный редактор для настраиваемых сочетаний клавиш, действий и записей палитры команд.
|
||||
– Новые локализации сообщества на сербский и украинский языки
|
||||
– Поддержка протокола клавиатуры Kitty для высокоточного кодирования ввода
|
||||
– Новая страница расширений, на которой отображается информация о том, что было установлено в вашем терминале
|
||||
– Палитра команд теперь доступна на вашем языке, а также на английском
|
||||
– Новые функции VT, например синхронизированная отрисовка, новые цветовые схемы, настройка быстрых действий мыши, таких как масштабирование, и т. д.
|
||||
|
||||
Дополнительные сведения см. на странице выпусков GitHub.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ProductDescription language="sr-cyrl-rs" xmlns="http://schemas.microsoft.com/appx/2012/ProductDescription" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:lang="en-us" Release="">
|
||||
<AppStoreName _locID="App_AppStoreName">
|
||||
<!-- This is optional. AppStoreName is typically extracted from your package's AppxManifest DisplayName property. -->
|
||||
<!-- Uncomment (and localize) this Store name if your application package does not contain a localization for the DisplayName in this language. -->
|
||||
<!-- Leaving this uncommented for a language that your application package DOES contain a DisplayName for will result in a submission failure with the API. -->
|
||||
<!-- _locComment_text="{MaxLength=200} App AppStoreName" -->
|
||||
<!-- Windows Terminal -->
|
||||
</AppStoreName>
|
||||
<Keywords>
|
||||
<!-- Valid length: 30 character limit, up to 7 elements -->
|
||||
<Keyword _locID="App_keyword1">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 1" -->Терминал</Keyword>
|
||||
<Keyword _locID="App_keyword2">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 2" -->Конзола</Keyword>
|
||||
<Keyword _locID="App_keyword3">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 3" -->
|
||||
</Keyword>
|
||||
<Keyword _locID="App_keyword4">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 4" -->
|
||||
</Keyword>
|
||||
<Keyword _locID="App_keyword5">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 5" -->
|
||||
</Keyword>
|
||||
<Keyword _locID="App_keyword6">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 6" -->
|
||||
</Keyword>
|
||||
<Keyword _locID="App_keyword7">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 7" -->
|
||||
</Keyword>
|
||||
</Keywords>
|
||||
<Description _locID="App_Description">
|
||||
<!-- _locComment_text="{MaxLength=10000} App Description" -->Ово је изградња прегледа апликације Windows терминал. Она садржи најновије могућности које се још увек развијају. Windows терминал је модерна, брза, ефикасна, моћна и продуктивна апликација терминала за кориснике алата из командне линије и љуски као што су Command Prompt, PowerShell, и WSL. Неке од његових главних функционалности су вишеструке картице, панели, подршка за Уникод и UTF-8, GPU убрзани механизам за исцртавање текста, произвољне теме, стилови и конфигурације.
|
||||
|
||||
Ово је пројекат отвореног кода и учешће заједнице је добродошло. Ако желите да учествујете, молимо вас да посетите https://github.com/microsoft/terminal </Description>
|
||||
<ShortDescription _locID="App_ShortDescription">
|
||||
<!-- Only used for games. This description appears in the Information section of the Game Hub on Xbox One, and helps customers understand more about your game. -->
|
||||
<!-- _locComment_text="{MaxLength=500} App ShortDescription" -->
|
||||
</ShortDescription>
|
||||
<ShortTitle _locID="App_ShortTitle">
|
||||
<!-- A shorter version of your product's name. If provided, this shorter name may appear in various places on Xbox One (during installation, in Achievements, etc.) in place of the full title of your product. -->
|
||||
<!-- _locComment_text="{MaxLength=50} App ShortTitle" -->
|
||||
</ShortTitle>
|
||||
<SortTitle _locID="App_SortTitle">
|
||||
<!-- If your product could be alphabetized in different ways, you can enter another version here. This may help customers find the product more quickly when searching. -->
|
||||
<!-- _locComment_text="{MaxLength=255} App SortTitle" -->
|
||||
</SortTitle>
|
||||
<VoiceTitle _locID="App_VoiceTitle">
|
||||
<!-- An alternate name for your product that, if provided, may be used in the audio experience on Xbox One when using Kinect or a headset. -->
|
||||
<!-- _locComment_text="{MaxLength=255} App VoiceTitle" -->
|
||||
</VoiceTitle>
|
||||
<DevStudio _locID="App_DevStudio">
|
||||
<!-- Specify this value if you want to include a "Developed by" field in the listing. (The "Published by" field will list the publisher display name associated with your account, whether or not you provide a devStudio value.) -->
|
||||
<!-- _locComment_text="{MaxLength=255} App DevStudio" -->
|
||||
</DevStudio>
|
||||
<ReleaseNotes _locID="App_ReleaseNotes">
|
||||
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe}{Locked=Kitty} App Release Note" -->Верзија __VERSION_NUMBER__
|
||||
|
||||
- Коначно, могућност претраге било ког подешавања!
|
||||
- Нови својствени едитор ставки пречица на тастатури, акција и командне палете
|
||||
- Нова локализација заједнице на српски и украјински језик
|
||||
- Подршка за „Kitty” протокол тастатуре који омогућава верно кодирање уноса
|
||||
|
||||
За више детаља, молимо вас да посетите нашу GitHub страницу издања.
|
||||
</ReleaseNotes>
|
||||
<ScreenshotCaptions>
|
||||
<!-- Valid length: 200 character limit, up to 9 elements per platform -->
|
||||
<!-- Valid attributes: any of DesktopImage, MobileImage, XboxImage, SurfaceHubImage, and HoloLensImage -->
|
||||
<Caption DesktopImage="acrylic-emoji.png" _locID="App_caption1">
|
||||
<!-- _locComment_text="{MaxLength=200} Screenshot caption 1" -->
|
||||
</Caption>
|
||||
<Caption DesktopImage="panes.png" _locID="App_caption2">
|
||||
<!-- _locComment_text="{MaxLength=200} Screenshot caption 2" -->
|
||||
</Caption>
|
||||
<Caption DesktopImage="htop.png" _locID="App_caption3">
|
||||
<!-- _locComment_text="{MaxLength=200} Screenshot caption 3" -->
|
||||
</Caption>
|
||||
</ScreenshotCaptions>
|
||||
<AdditionalAssets>
|
||||
<!-- Valid elements:-->
|
||||
<!-- HeroImage414x180, HeroImage846x468, HeroImage558x756, HeroImage414x468, HeroImage558x558, HeroImage2400x1200,-->
|
||||
<!-- ScreenshotWXGA, ScreenshotHD720, ScreenshotWVGA, Doublewide, Panoramic, Square,-->
|
||||
<!-- SmallMobileTile, SmallXboxLiveTile, LargeMobileTile, LargeXboxLiveTile, Tile,-->
|
||||
<!-- DesktopIcon, Icon (use this value for the 1:1 300x300 pixels logo), AchievementIcon,-->
|
||||
<!-- ChallengePromoIcon, RewardDisplayIcon, Icon150X150, Icon71X71,-->
|
||||
<!-- BoxArt, BrandedKeyArt, PosterArt, FeaturedPromotionalArt, PromotionalArt16x9, TitledHeroArt-->
|
||||
<!-- There is no content for any of these elements, just a single attribute called FileName. -->
|
||||
<PosterArt FileName="Store Poster Art.png" />
|
||||
<BoxArt FileName="Store Box Art.png" />
|
||||
<PromotionalArt16x9 FileName="Store Thumbnail.png" />
|
||||
</AdditionalAssets>
|
||||
<Trailers>
|
||||
<!-- Maximum number of trailers permitted: 15 -->
|
||||
<Trailer FileName="CC0605_CommandLine_Teaser_WEB_MASTER_H264_1080p_23.976_-16LKFS_-3dbTP_ST.mp4">
|
||||
<Title _locID="App_trailerTitle1">
|
||||
<!-- _locComment_text="{MaxLength=255} Trailer title 1" -->Нови Windows терминал</Title>
|
||||
<Images>
|
||||
<!-- Current maximum of 1 image per trailer permitted. -->
|
||||
<Image FileName="Store Thumbnail.png">
|
||||
<!-- _locComment_text="{Locked} Trailer screenshot 1 description" -->
|
||||
</Image>
|
||||
</Images>
|
||||
</Trailer>
|
||||
</Trailers>
|
||||
<AppFeatures>
|
||||
<!-- Valid length: 200 character limit, up to 20 elements -->
|
||||
<AppFeature _locID="App_feature1">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 1" -->Вишеструке картице</AppFeature>
|
||||
<AppFeature _locID="App_feature2">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 2" -->Пуна Уникод подршка</AppFeature>
|
||||
<AppFeature _locID="App_feature3">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 3" -->GPU-убрзано исцртавање текста</AppFeature>
|
||||
<AppFeature _locID="App_feature4">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 4" -->Потпуна прилагодљивост</AppFeature>
|
||||
<AppFeature _locID="App_feature5">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 5" -->Подела панела</AppFeature>
|
||||
<AppFeature _locID="App_feature6">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 6" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature7">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 7" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature8">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 8" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature9">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 9" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature10">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 10" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature11">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 11" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature12">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 12" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature13">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 13" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature14">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 14" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature15">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 15" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature16">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 16" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature17">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 17" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature18">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 18" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature19">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 19" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature20">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 20" -->
|
||||
</AppFeature>
|
||||
</AppFeatures>
|
||||
<RecommendedHardware>
|
||||
<!-- Valid length: 200 character limit, up to 11 elements -->
|
||||
<Recommendation _locID="App_RecommendedHW1">
|
||||
<!-- _locComment_text="{MaxLength=200} App Recommended Hardware 1" -->Тастатура</Recommendation>
|
||||
</RecommendedHardware>
|
||||
<MinimumHardware>
|
||||
<!-- Valid length: 200 character limit, up to 11 elements -->
|
||||
</MinimumHardware>
|
||||
<CopyrightAndTrademark _locID="App_CopyrightandTrademark">
|
||||
<!-- _locComment_text="{MaxLength=200} Copyright and Trademark" -->Copyright (c) Microsoft Corporation</CopyrightAndTrademark>
|
||||
<AdditionalLicenseTerms _locID="App_AdditionalLicenseTerms">
|
||||
<!-- _locComment_text="{MaxLength=10000} Additional License Terms" -->
|
||||
</AdditionalLicenseTerms>
|
||||
<WebsiteURL _locID="App_WebsiteURL">
|
||||
<!-- _locComment_text="{MaxLength=2048} WebsiteURL" -->https://github.com/microsoft/terminal</WebsiteURL>
|
||||
<SupportContactInfo _locID="App_SupportContactInfo">
|
||||
<!-- _locComment_text="{MaxLength=2048} Support Contact Info" -->https://github.com/microsoft/terminal/issues/new</SupportContactInfo>
|
||||
<PrivacyPolicyURL _locID="App_PrivacyURL">
|
||||
<!-- _locComment_text="{MaxLength=2048} Privacy Policy URL" -->https://go.microsoft.com/fwlink/?LinkID=521839</PrivacyPolicyURL>
|
||||
</ProductDescription>
|
||||
@@ -56,10 +56,9 @@
|
||||
<ReleaseNotes _locID="App_ReleaseNotes">
|
||||
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe} App Release Note" -->Версія __VERSION_NUMBER__
|
||||
|
||||
- Нарешті, можливість пошуку будь-якого налаштування!
|
||||
- Новий вбудований редактор для прив'язки клавіш, дій та палітри команд.
|
||||
- Нові локалізації спільноти на сербську та українську мови.
|
||||
- Підтримка протоколу клавіатури "Kitty" для високоточного кодування введення.
|
||||
- Цілком нова сторінка розширень, яка показує, що було встановлено у вашому терміналі
|
||||
- Палітра команд тепер відображається вашою рідною мовою, а також англійською
|
||||
- Нові функції віртуального автомата, такі як синхронізований рендеринг, нові колірні схеми, налаштування для швидких дій миші, таких як масштабування, тощо
|
||||
|
||||
Будь ласка, перегляньте нашу сторінку релізів GitHub для отримання додаткової інформації.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,10 +56,9 @@
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
- 终于可以搜索任何设置了!
|
||||
- 新增用于键绑定、操作和命令面板条目的原生编辑器。
|
||||
- 新增塞尔维亚语和乌克兰语社区本地化支持
|
||||
- 支持 "Kitty" 键盘协议,实现高保真输入编码
|
||||
- 一个全新的“扩展”页,显示已安装到终端的内容
|
||||
- 命令面板现在以你的母语和英语显示
|
||||
- 新的 VT 功能,例如同步渲染、新配色方案、快速鼠标操作(如缩放)的配置等
|
||||
|
||||
有关其他详细信息,请参阅我们的 GitHub 发布页面。
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,10 +56,9 @@
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
- 終於,提供可搜尋任何設定的功能!
|
||||
- 全新原生編輯器,支援按鍵繫結、動作及命令選擇區項目。
|
||||
- 新增社群本地語系化,包含塞爾維亞語與烏克蘭語
|
||||
- 支援高保真度輸入編碼的「Kitty」鍵盤通訊協定
|
||||
- 全新的延伸模組頁面會顯示已安裝在您終端機中的內容
|
||||
- 命令選擇區現在以您的母語和英文顯示
|
||||
- 新的 VT 功能,例如同步轉譯、新的色彩配置、快速滑鼠動作 (例如縮放) 設定等等
|
||||
|
||||
如需更多詳細資料,請參閱我們的 GitHub 發行版本頁面。
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,9 +56,9 @@ Dies ist ein Open Source-Projekt, und wir freuen uns über die Teilnahme an der
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
– Eine komplett neue Erweiterungsseite, die anzeigt, was in Ihrem Terminal installiert ist
|
||||
– Die Befehlspalette wird jetzt sowohl in Ihrer Muttersprache als auch auf Englisch angezeigt
|
||||
– Neue VT-Features wie synchronisiertes Rendering, neue Farbschemas, Konfiguration für schnelle Mausaktionen wie Zoomen und mehr
|
||||
– Wir haben der Benutzeroberfläche Dutzende von Einstellungen hinzugefügt, die nur einmal in der JSON-Datei vorhanden waren, einschließlich einer neuen Seite zum Anpassen des Layouts Ihres Menüs „Neue Registerkarte“!
|
||||
– Wir haben die Fensterverwaltung umgestaltet, um die Zuverlässigkeit zu verbessern. Melden Sie alle Fehler, die beim alias „wt.exe“ auftreten
|
||||
– Profile zeigen jetzt ein Symbol an, wenn sie ausgeblendet wurden oder auf Programme verweisen, die deinstalliert wurden.
|
||||
|
||||
Weitere Informationen finden Sie auf unserer GitHub-Releaseseite.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,9 +56,9 @@ This is an open source project and we welcome community participation. To partic
|
||||
<ReleaseNotes _locID="App_ReleaseNotes">
|
||||
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe} App Release Note" -->Version __VERSION_NUMBER__
|
||||
|
||||
- A whole new Extensions page that shows what has been installed into your Terminal
|
||||
- Command Palette now shows up in your native language as well as English
|
||||
- New VT features such as synchronized rendering, new color schemes, configuration for quick mouse actions like zooming, and more
|
||||
- We've added dozens of settings to the UI that once only existed in the JSON file, including a new page for customizing the layout of your New Tab menu!
|
||||
- We have rearchitected window management to improve reliability; please file any bugs you encounter with the wt.exe alias
|
||||
- Profiles now show an icon if they've been hidden or refer to programs which were uninstalled.
|
||||
|
||||
Please see our GitHub releases page for additional details.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,9 +56,9 @@ Este es un proyecto de fuente abierta y animamos a la comunidad a participar. Pa
|
||||
<ReleaseNotes>
|
||||
Versión __VERSION_NUMBER__
|
||||
|
||||
- Página Extensiones completamente nueva que muestra lo que se ha instalado en tu terminal
|
||||
- La paleta de comandos ahora se muestra en tu idioma nativo, así como en inglés
|
||||
- Nuevas características de VT, como la representación sincronizada, nuevos esquemas de color, configuración para acciones rápidas del ratón, como el zoom, y más
|
||||
- Hemos añadido decenas de configuraciones a la interfaz de usuario que antes solo existían en el archivo JSON, incluida una nueva página para personalizar el diseño del menú Nueva pestaña.
|
||||
- Hemos reestructurado la gestión de ventanas para mejorar la fiabilidad; informe de cualquier error que encuentre con el alias wt.exe
|
||||
- Ahora, los perfiles muestran un icono si han sido ocultados o hacen referencia a programas que han sido desinstalados.
|
||||
|
||||
Consulte la página de versiones de GitHub para más información.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,11 +56,11 @@ Il s’agit d’un projet open source et nous encourageons la participation à l
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
- Une toute nouvelle page Extensions qui affiche ce qui a été installé dans votre Terminal
|
||||
- La palette de commandes s’affiche désormais dans votre langue native, ainsi qu’en anglais
|
||||
- De nouvelles fonctionnalités VT, telles que le rendu synchronisé, de nouveaux schémas de couleurs, une configuration pour des actions rapides de la souris comme le zoom, et bien plus encore
|
||||
- Nous avons ajouté des dizaines de paramètres à l’interface utilisateur qui n’existaient auparavant que dans le fichier JSON, y compris une nouvelle page pour personnaliser la disposition de votre menu Nouvel onglet.
|
||||
- Nous avons fait une refonte de la gestion des fenêtres pour améliorer la fiabilité. Veuillez signaler les bogues que vous rencontrez avec l’alias wt.exe.
|
||||
- Les profils affichent désormais une icône s’ils ont été masqués ou s’ils font référence à des programmes qui ont été désinstallés.
|
||||
|
||||
Consultez notre page des versions de GitHub pour plus de détails.
|
||||
Veuillez consulter notre page des versions GitHub pour découvrir d’autres détails.
|
||||
</ReleaseNotes>
|
||||
<ScreenshotCaptions>
|
||||
<!-- Valid length: 200 character limit, up to 9 elements per platform -->
|
||||
|
||||
@@ -56,9 +56,9 @@ Si tratta di un progetto open source e la partecipazione della community è molt
|
||||
<ReleaseNotes>
|
||||
Versione __VERSION_NUMBER__
|
||||
|
||||
- Una pagina Estensioni completamente nuova che mostra ciò che è stato installato nel terminale
|
||||
- Il riquadro comandi ora viene visualizzato nella tua lingua di origine oltre che in inglese
|
||||
- Nuove funzionalità VT come il rendering sincronizzato, le nuove combinazioni di colori, la configurazione per azioni rapide del mouse come lo zoom e altro ancora
|
||||
- Abbiamo aggiunto decine di impostazioni all'interfaccia utente che in precedenza esistevano solo nel file JSON, inclusa una nuova pagina per personalizzare il layout del menu Nuova scheda.
|
||||
- Abbiamo riprogettato la gestione delle finestre per migliorarne l'affidabilità; segnala eventuali bug riscontrati con l'alias wt.exe
|
||||
- I profili ora mostrano un'icona se sono stati nascosti o se fanno riferimento a programmi disinstallati.
|
||||
|
||||
Per altri dettagli, vedi la pagina delle release di GitHub.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
<ReleaseNotes>
|
||||
バージョン __VERSION_NUMBER__
|
||||
|
||||
- お使いのターミナルに何がインストールされているかを表示する新しい [拡張機能] ページ
|
||||
- コマンド パレットがネイティブ言語と英語で表示されるようになりました
|
||||
- 同期レンダリング、新しい配色、ズームなどのクイック マウス操作の構成などの、新しい VT 機能
|
||||
- 新しいタブ メニューのレイアウトをカスタマイズするための新しいページなど、以前は JSON ファイルにしかなかった設定が UI に多数追加されました。
|
||||
- 信頼性を向上させるために、ウィンドウ管理を再設計しました。wt.exe エイリアスで発生したバグを報告してください
|
||||
- プロファイルが非表示になっている場合や、アンインストールされたプログラムを参照している場合に、アイコンが表示されるようになりました。
|
||||
|
||||
詳細については、GitHub リリース ページをご覧ください。
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,11 +56,11 @@
|
||||
<ReleaseNotes>
|
||||
버전 __VERSION_NUMBER__
|
||||
|
||||
- 터미널에 설치된 항목을 보여 주는 완전히 새로운 확장 페이지
|
||||
- 이제 영어뿐만 아니라 모국어로도 표시되는 명령 팔레트
|
||||
- 동기화된 렌더링, 새로운 색 구성표, 확대/축소와 같은 빠른 마우스 동작을 위한 구성 등 새로운 VT 기능 추가
|
||||
- 새 탭 메뉴의 레이아웃을 사용자 지정하기 위한 새 페이지를 포함하여 JSON 파일에만 존재했던 수십 개의 설정을 UI에 추가
|
||||
- 안정성을 개선하기 위해 창 관리 구조를 재구성했습니다. wt.exe 별칭과 관련하여 발생한 버그 신고
|
||||
- 프로필이 숨겨졌거나 제거된 프로그램을 참조하는 경우 이제 프로필에 아이콘이 표시됩니다.
|
||||
|
||||
자세한 정보는 GitHub 릴리스 페이지를 참고하세요.
|
||||
자세한 내용은 GitHub 릴리스 페이지를 참조하세요.
|
||||
</ReleaseNotes>
|
||||
<ScreenshotCaptions>
|
||||
<!-- Valid length: 200 character limit, up to 9 elements per platform -->
|
||||
|
||||
@@ -56,9 +56,9 @@ Este é um projeto de código aberto e a participação da comunidade é bem-vin
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
– Uma nova página de Extensões que mostra o que foi instalado no seu Terminal
|
||||
– A Paleta de Comandos agora aparece no seu idioma nativo, além do inglês
|
||||
– Novos recursos da VT, como renderização sincronizada, novos esquemas de cores, configuração para ações rápidas do mouse, como zoom, e muito mais
|
||||
– Adicionamos várias configurações à interface do usuário que antes só existiam no arquivo JSON, incluindo uma nova página para personalizar o layout do seu menu Nova Guia!
|
||||
– Reestruturamos o gerenciamento de janelas para melhorar a confiabilidade; registre os bugs que você encontrar com o alias wt.exe
|
||||
– Os perfis agora exibem um ícone se estiverem ocultos ou se referirem a programas que foram desinstalados.
|
||||
|
||||
Confira nossa página de lançamentos no GitHub para obter mais detalhes.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
<ReleaseNotes>
|
||||
Версия __VERSION_NUMBER__
|
||||
|
||||
– Новая страница расширений, на которой отображается информация о том, что было установлено в вашем терминале
|
||||
– Палитра команд теперь доступна на вашем языке, а также на английском
|
||||
– Новые функции VT, например синхронизированная отрисовка, новые цветовые схемы, настройка быстрых действий мыши, таких как масштабирование, и т. д.
|
||||
– Мы добавили в пользовательский интерфейс десятки параметров, которые ранее существовали только в JSON-файле, включая новую страницу для настройки макета меню новой вкладки.
|
||||
– Мы переработали управление окнами для повышения надежности. Сообщайте о любых ошибках, которые вы обнаружите с псевдонимом wt.exe
|
||||
– Профили теперь отображают значок, если они были скрыты или ссылаются на программы, которые были удалены.
|
||||
|
||||
Дополнительные сведения см. на странице выпусков GitHub.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ProductDescription language="sr-cyrl-rs" xmlns="http://schemas.microsoft.com/appx/2012/ProductDescription" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:lang="en-us" Release="">
|
||||
<AppStoreName _locID="App_AppStoreName">
|
||||
<!-- This is optional. AppStoreName is typically extracted from your package's AppxManifest DisplayName property. -->
|
||||
<!-- Uncomment (and localize) this Store name if your application package does not contain a localization for the DisplayName in this language. -->
|
||||
<!-- Leaving this uncommented for a language that your application package DOES contain a DisplayName for will result in a submission failure with the API. -->
|
||||
<!-- _locComment_text="{MaxLength=200} App AppStoreName" -->
|
||||
<!-- Windows Terminal -->
|
||||
</AppStoreName>
|
||||
<Keywords>
|
||||
<!-- Valid length: 30 character limit, up to 7 elements -->
|
||||
<Keyword _locID="App_keyword1">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 1" -->Терминал</Keyword>
|
||||
<Keyword _locID="App_keyword2">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 2" -->Конзола</Keyword>
|
||||
<Keyword _locID="App_keyword3">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 3" -->
|
||||
</Keyword>
|
||||
<Keyword _locID="App_keyword4">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 4" -->
|
||||
</Keyword>
|
||||
<Keyword _locID="App_keyword5">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 5" -->
|
||||
</Keyword>
|
||||
<Keyword _locID="App_keyword6">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 6" -->
|
||||
</Keyword>
|
||||
<Keyword _locID="App_keyword7">
|
||||
<!-- _locComment_text="{MaxLength=30} App keyword 7" -->
|
||||
</Keyword>
|
||||
</Keywords>
|
||||
<Description _locID="App_Description">
|
||||
<!-- _locComment_text="{MaxLength=10000} App Description" -->Windows терминал је модерна, брза, ефикасна, моћна и продуктивна апликација терминала за кориснике алата из командне линије и љуски као што су Command Prompt, PowerShell, и WSL. Неке од његових главних функционалности су вишеструке картице, панели, подршка за Уникод и UTF-8, GPU убрзани механизам за исцртавање текста, произвољне теме, стилови и конфигурације.
|
||||
|
||||
Ово је пројекат отвореног кода и учешће заједнице је добродошло. Ако желите да учествујете, молимо вас да посетите https://github.com/microsoft/terminal </Description>
|
||||
<ShortDescription _locID="App_ShortDescription">
|
||||
<!-- Only used for games. This description appears in the Information section of the Game Hub on Xbox One, and helps customers understand more about your game. -->
|
||||
<!-- _locComment_text="{MaxLength=500} App ShortDescription" -->
|
||||
</ShortDescription>
|
||||
<ShortTitle _locID="App_ShortTitle">
|
||||
<!-- A shorter version of your product's name. If provided, this shorter name may appear in various places on Xbox One (during installation, in Achievements, etc.) in place of the full title of your product. -->
|
||||
<!-- _locComment_text="{MaxLength=50} App ShortTitle" -->
|
||||
</ShortTitle>
|
||||
<SortTitle _locID="App_SortTitle">
|
||||
<!-- If your product could be alphabetized in different ways, you can enter another version here. This may help customers find the product more quickly when searching. -->
|
||||
<!-- _locComment_text="{MaxLength=255} App SortTitle" -->
|
||||
</SortTitle>
|
||||
<VoiceTitle _locID="App_VoiceTitle">
|
||||
<!-- An alternate name for your product that, if provided, may be used in the audio experience on Xbox One when using Kinect or a headset. -->
|
||||
<!-- _locComment_text="{MaxLength=255} App VoiceTitle" -->
|
||||
</VoiceTitle>
|
||||
<DevStudio _locID="App_DevStudio">
|
||||
<!-- Specify this value if you want to include a "Developed by" field in the listing. (The "Published by" field will list the publisher display name associated with your account, whether or not you provide a devStudio value.) -->
|
||||
<!-- _locComment_text="{MaxLength=255} App DevStudio" -->
|
||||
</DevStudio>
|
||||
<ReleaseNotes _locID="App_ReleaseNotes">
|
||||
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe} App Release Note" -->Верзија __VERSION_NUMBER__
|
||||
|
||||
- Попуно нова страница Проширења која приказује шта је све инсталирано у ваш Терминал
|
||||
- Палета команди се сада приказује и на вашем матерњем језику, као и на енглеском
|
||||
- Нове VT функционалности као што су синхронизовано исцртавање, нове шеме боја, конфигурација за брзе акције мишем, као што је зумирање, и још тога
|
||||
|
||||
За више детаља, молимо вас да посетите нашу GitHub страницу издања.
|
||||
</ReleaseNotes>
|
||||
<ScreenshotCaptions>
|
||||
<!-- Valid length: 200 character limit, up to 9 elements per platform -->
|
||||
<!-- Valid attributes: any of DesktopImage, MobileImage, XboxImage, SurfaceHubImage, and HoloLensImage -->
|
||||
<Caption DesktopImage="acrylic-emoji.png" _locID="App_caption1">
|
||||
<!-- _locComment_text="{MaxLength=200} Screenshot caption 1" -->
|
||||
</Caption>
|
||||
<Caption DesktopImage="panes.png" _locID="App_caption2">
|
||||
<!-- _locComment_text="{MaxLength=200} Screenshot caption 2" -->
|
||||
</Caption>
|
||||
<Caption DesktopImage="htop.png" _locID="App_caption3">
|
||||
<!-- _locComment_text="{MaxLength=200} Screenshot caption 3" -->
|
||||
</Caption>
|
||||
</ScreenshotCaptions>
|
||||
<AdditionalAssets>
|
||||
<!-- Valid elements:-->
|
||||
<!-- HeroImage414x180, HeroImage846x468, HeroImage558x756, HeroImage414x468, HeroImage558x558, HeroImage2400x1200,-->
|
||||
<!-- ScreenshotWXGA, ScreenshotHD720, ScreenshotWVGA, Doublewide, Panoramic, Square,-->
|
||||
<!-- SmallMobileTile, SmallXboxLiveTile, LargeMobileTile, LargeXboxLiveTile, Tile,-->
|
||||
<!-- DesktopIcon, Icon (use this value for the 1:1 300x300 pixels logo), AchievementIcon,-->
|
||||
<!-- ChallengePromoIcon, RewardDisplayIcon, Icon150X150, Icon71X71,-->
|
||||
<!-- BoxArt, BrandedKeyArt, PosterArt, FeaturedPromotionalArt, PromotionalArt16x9, TitledHeroArt-->
|
||||
<!-- There is no content for any of these elements, just a single attribute called FileName. -->
|
||||
<PosterArt FileName="Store Poster Art.png" />
|
||||
<BoxArt FileName="Store Box Art.png" />
|
||||
<PromotionalArt16x9 FileName="Store Thumbnail.png" />
|
||||
</AdditionalAssets>
|
||||
<Trailers>
|
||||
<!-- Maximum number of trailers permitted: 15 -->
|
||||
<Trailer FileName="CC0605_CommandLine_Teaser_WEB_MASTER_H264_1080p_23.976_-16LKFS_-3dbTP_ST.mp4">
|
||||
<Title _locID="App_trailerTitle1">
|
||||
<!-- _locComment_text="{MaxLength=255} Trailer title 1" -->Нови Windows терминал</Title>
|
||||
<Images>
|
||||
<!-- Current maximum of 1 image per trailer permitted. -->
|
||||
<Image FileName="Store Thumbnail.png">
|
||||
<!-- _locComment_text="{Locked} Trailer screenshot 1 description" -->
|
||||
</Image>
|
||||
</Images>
|
||||
</Trailer>
|
||||
</Trailers>
|
||||
<AppFeatures>
|
||||
<!-- Valid length: 200 character limit, up to 20 elements -->
|
||||
<AppFeature _locID="App_feature1">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 1" -->Вишеструке картице</AppFeature>
|
||||
<AppFeature _locID="App_feature2">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 2" -->Пуна Уникод подршка</AppFeature>
|
||||
<AppFeature _locID="App_feature3">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 3" -->GPU-убрзано исцртавање текста</AppFeature>
|
||||
<AppFeature _locID="App_feature4">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 4" -->Потпуна прилагодљивост</AppFeature>
|
||||
<AppFeature _locID="App_feature5">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 5" -->Подела панела</AppFeature>
|
||||
<AppFeature _locID="App_feature6">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 6" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature7">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 7" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature8">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 8" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature9">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 9" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature10">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 10" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature11">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 11" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature12">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 12" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature13">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 13" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature14">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 14" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature15">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 15" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature16">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 16" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature17">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 17" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature18">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 18" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature19">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 19" -->
|
||||
</AppFeature>
|
||||
<AppFeature _locID="App_feature20">
|
||||
<!-- _locComment_text="{MaxLength=200} App Feature 20" -->
|
||||
</AppFeature>
|
||||
</AppFeatures>
|
||||
<RecommendedHardware>
|
||||
<!-- Valid length: 200 character limit, up to 11 elements -->
|
||||
<Recommendation _locID="App_RecommendedHW1">
|
||||
<!-- _locComment_text="{MaxLength=200} App Recommended Hardware 1" -->Тастатура</Recommendation>
|
||||
</RecommendedHardware>
|
||||
<MinimumHardware>
|
||||
<!-- Valid length: 200 character limit, up to 11 elements -->
|
||||
</MinimumHardware>
|
||||
<CopyrightAndTrademark _locID="App_CopyrightandTrademark">
|
||||
<!-- _locComment_text="{MaxLength=200} Copyright and Trademark" -->Copyright (c) Microsoft Corporation</CopyrightAndTrademark>
|
||||
<AdditionalLicenseTerms _locID="App_AdditionalLicenseTerms">
|
||||
<!-- _locComment_text="{MaxLength=10000} Additional License Terms" -->
|
||||
</AdditionalLicenseTerms>
|
||||
<WebsiteURL _locID="App_WebsiteURL">
|
||||
<!-- _locComment_text="{MaxLength=2048} WebsiteURL" -->https://github.com/microsoft/terminal</WebsiteURL>
|
||||
<SupportContactInfo _locID="App_SupportContactInfo">
|
||||
<!-- _locComment_text="{MaxLength=2048} Support Contact Info" -->https://github.com/microsoft/terminal/issues/new</SupportContactInfo>
|
||||
<PrivacyPolicyURL _locID="App_PrivacyURL">
|
||||
<!-- _locComment_text="{MaxLength=2048} Privacy Policy URL" -->https://go.microsoft.com/fwlink/?LinkID=521839</PrivacyPolicyURL>
|
||||
</ProductDescription>
|
||||
@@ -56,9 +56,9 @@
|
||||
<ReleaseNotes _locID="App_ReleaseNotes">
|
||||
<!-- _locComment_text="{MaxLength=1500} {Locked=__VERSION_NUMBER__}{Locked=wt.exe} App Release Note" -->Версія __VERSION_NUMBER__
|
||||
|
||||
- Цілком нова сторінка розширень, яка показує, що було встановлено у вашому Терміналі
|
||||
- Палітра команд тепер відображається вашою рідною мовою, так само, як і англійською
|
||||
- Нові VT функції, такі як синхронізований рендеринг, нові колірні схеми, налаштування для швидких дій миші, таких як масштабування, тощо
|
||||
- Ми додали десятки налаштувань до інтерфейсу користувача, які раніше існували лише у файлі JSON, включаючи нову сторінку для налаштування макета меню «Нова вкладка»!
|
||||
- Ми переробили архітектуру керування вікнами для підвищення надійності; будь ласка, повідомляйте про будь-які помилки, з якими ви зіткнулися, за допомогою псевдоніма wt.exe.
|
||||
- Профілі тепер відображають значок, якщо вони були приховані, або посилаються на програми, які було видалено.
|
||||
|
||||
Будь ласка, перегляньте нашу сторінку релізів GitHub для отримання додаткової інформації.
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
- 一个全新的“扩展”页,显示已安装到终端的内容
|
||||
- 命令面板现在以你的母语和英语显示
|
||||
- 新的 VT 功能,例如同步渲染、新配色方案、快速鼠标操作(如缩放)的配置等
|
||||
- 我们向用户界面添加了许多之前仅存在于 JSON 文件中的设置,包括用于自定义“新建标签页”菜单布局的新页面!
|
||||
- 我们已重新架构窗口管理以提高可靠性; 请使用 wt.exe 别名提交您遇到的任何错误
|
||||
- 配置文件如果已被隐藏或引用了已卸载的程序,现在会显示一个图标。
|
||||
|
||||
有关其他详细信息,请参阅我们的 GitHub 发布页面。
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
<ReleaseNotes>
|
||||
Version __VERSION_NUMBER__
|
||||
|
||||
- 全新的延伸模組頁面會顯示已安裝在您終端機中的內容
|
||||
- 命令選擇區現在以您的母語和英文顯示
|
||||
- 新的 VT 功能,例如同步轉譯、新的色彩配置、快速滑鼠動作 (例如縮放) 設定等等
|
||||
- 我們已在使用者介面中新增數十個曾經僅存在於 JSON 檔案中的設定,包括一個可自訂新索引標籤選單版面配置的新頁面!
|
||||
- 我們已重新架構視窗管理以提升可靠性; 如果您在使用 wt.exe 別名時遇到任何錯誤,請提交錯誤回報
|
||||
- 如果設定檔已隱藏或參照已解除安裝的程式,現在會顯示圖示。
|
||||
|
||||
如需更多詳細資料,請參閱我們的 GitHub 發行版本頁面。
|
||||
</ReleaseNotes>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
|
||||
<PGOBranch>main</PGOBranch>
|
||||
<PGOBranch>release-1.25</PGOBranch>
|
||||
|
||||
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
|
||||
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2026</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>26</VersionMinor>
|
||||
<VersionMinor>25</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
<VersionInfoCulture>1033</VersionInfoCulture>
|
||||
<!-- The default has a spacing problem -->
|
||||
|
||||
@@ -3174,11 +3174,6 @@
|
||||
"mingw"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"dragDropDelimiter": {
|
||||
"default": " ",
|
||||
"description": "The delimiter used when dropping multiple files onto the terminal.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -350,7 +350,7 @@ void ROW::_init() noexcept
|
||||
std::iota(_charOffsets.begin(), _charOffsets.end(), uint16_t{ 0 });
|
||||
#endif
|
||||
|
||||
#pragma warning(pop)
|
||||
#pragma warning(push)
|
||||
}
|
||||
|
||||
void ROW::CopyFrom(const ROW& source)
|
||||
@@ -1143,6 +1143,13 @@ til::CoordType ROW::GetTrailingColumnAtCharOffset(const ptrdiff_t offset) const
|
||||
return _createCharToColumnMapper(offset).GetTrailingColumnAt(offset);
|
||||
}
|
||||
|
||||
uint16_t ROW::GetCharOffset(til::CoordType col) const noexcept
|
||||
{
|
||||
const auto columns = GetReadableColumnCount();
|
||||
const auto colBeg = clamp(col, 0, columns);
|
||||
return _uncheckedCharOffset(gsl::narrow_cast<size_t>(colBeg));
|
||||
}
|
||||
|
||||
DelimiterClass ROW::DelimiterClassAt(til::CoordType column, const std::wstring_view& wordDelimiters) const noexcept
|
||||
{
|
||||
const auto col = _clampedColumn(column);
|
||||
|
||||
@@ -172,6 +172,7 @@ public:
|
||||
std::wstring_view GetText(til::CoordType columnBegin, til::CoordType columnEnd) const noexcept;
|
||||
til::CoordType GetLeadingColumnAtCharOffset(ptrdiff_t offset) const noexcept;
|
||||
til::CoordType GetTrailingColumnAtCharOffset(ptrdiff_t offset) const noexcept;
|
||||
uint16_t GetCharOffset(til::CoordType col) const noexcept;
|
||||
DelimiterClass DelimiterClassAt(til::CoordType column, const std::wstring_view& wordDelimiters) const noexcept;
|
||||
|
||||
auto AttrBegin() const noexcept { return _attr.begin(); }
|
||||
|
||||
@@ -219,17 +219,6 @@ til::CoordType TextBuffer::_estimateOffsetOfLastCommittedRow() const noexcept
|
||||
return std::max(0, gsl::narrow_cast<til::CoordType>(lastRowOffset - 2));
|
||||
}
|
||||
|
||||
bool TextBuffer::_isRowCommitted(til::CoordType y) const noexcept
|
||||
{
|
||||
auto offset = (_firstRow + y + 1 /* account for the scratch row */) % _height;
|
||||
if (offset < 0)
|
||||
{
|
||||
offset += _height;
|
||||
}
|
||||
const auto row = _buffer.get() + _bufferRowStride * offset;
|
||||
return row < _commitWatermark;
|
||||
}
|
||||
|
||||
// Retrieves a row from the buffer by its offset from the first row of the text buffer
|
||||
// (what corresponds to the top row of the screen buffer).
|
||||
const ROW& TextBuffer::GetRowByOffset(const til::CoordType index) const
|
||||
@@ -945,10 +934,6 @@ void TextBuffer::ResetLineRenditionRange(const til::CoordType startRow, const ti
|
||||
|
||||
LineRendition TextBuffer::GetLineRendition(const til::CoordType row) const
|
||||
{
|
||||
if (!_isRowCommitted(row)) [[unlikely]]
|
||||
{
|
||||
return LineRendition::SingleWidth;
|
||||
}
|
||||
return GetRowByOffset(row).GetLineRendition();
|
||||
}
|
||||
|
||||
@@ -1156,20 +1141,7 @@ DelimiterClass TextBuffer::_GetDelimiterClassAt(const til::point pos, const std:
|
||||
return GetRowByOffset(realPos.y).DelimiterClassAt(realPos.x, wordDelimiters);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the start of the word at or before the given position
|
||||
// - When includeWhitespace is false, returns the start of the current delimiter class run
|
||||
// (selection behavior: stops at non-wrapped row boundaries)
|
||||
// - When includeWhitespace is true, also skips backward past any leading ControlChars
|
||||
// to include the preceding word (accessibility/UIA behavior: crosses all row boundaries)
|
||||
// Arguments:
|
||||
// - pos - the buffer position to start from
|
||||
// - wordDelimiters - characters considered as DelimiterClass::DelimiterChar
|
||||
// - includeWhitespace - when true, skip past leading whitespace to find the word start
|
||||
// - limitOptional - (optional) the last possible position in the buffer that can be explored
|
||||
// Return Value:
|
||||
// - The position of the first character of the word (inclusive)
|
||||
til::point TextBuffer::GetWordStart(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional) const
|
||||
til::point TextBuffer::GetWordStart2(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.BottomInclusiveRightExclusive()) };
|
||||
@@ -1202,7 +1174,7 @@ til::point TextBuffer::GetWordStart(til::point pos, const std::wstring_view word
|
||||
// 1. move to the beginning of the delimiter class run
|
||||
// 2. (includeWhitespace) if we were on a ControlChar, go back one more delimiter class run
|
||||
const auto initialDelimiter = bufferSize.IsInBounds(pos) ? _GetDelimiterClassAt(pos, wordDelimiters) : DelimiterClass::ControlChar;
|
||||
pos = _GetDelimiterClassRunStart(pos, wordDelimiters, includeWhitespace);
|
||||
pos = _GetDelimiterClassRunStart(pos, wordDelimiters);
|
||||
if (!includeWhitespace || pos.x == bufferSize.Left())
|
||||
{
|
||||
// Special case:
|
||||
@@ -1213,26 +1185,12 @@ til::point TextBuffer::GetWordStart(til::point pos, const std::wstring_view word
|
||||
else if (initialDelimiter == DelimiterClass::ControlChar)
|
||||
{
|
||||
bufferSize.DecrementInExclusiveBounds(pos);
|
||||
pos = _GetDelimiterClassRunStart(pos, wordDelimiters, includeWhitespace);
|
||||
pos = _GetDelimiterClassRunStart(pos, wordDelimiters);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the exclusive end of the word at or after the given position
|
||||
// - When includeWhitespace is false, returns the exclusive end of the current delimiter class run
|
||||
// (selection behavior: stops at non-wrapped row boundaries)
|
||||
// - When includeWhitespace is true, also skips forward past any trailing ControlChars
|
||||
// to include trailing whitespace (accessibility/UIA behavior: crosses all row boundaries)
|
||||
// - The result is clamped to limitOptional when provided
|
||||
// Arguments:
|
||||
// - pos - the buffer position to start from
|
||||
// - wordDelimiters - characters considered as DelimiterClass::DelimiterChar
|
||||
// - includeWhitespace - when true, skip past trailing whitespace to find the next word boundary
|
||||
// - limitOptional - (optional) the last possible position in the buffer that can be explored
|
||||
// Return Value:
|
||||
// - The exclusive end position of the word
|
||||
til::point TextBuffer::GetWordEnd(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional) const
|
||||
til::point TextBuffer::GetWordEnd2(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.BottomInclusiveRightExclusive()) };
|
||||
@@ -1265,12 +1223,8 @@ til::point TextBuffer::GetWordEnd(til::point pos, const std::wstring_view wordDe
|
||||
// So the heuristic we use is:
|
||||
// 1. move to the end of the delimiter class run
|
||||
// 2. (includeWhitespace) if the next delimiter class run is a ControlChar, go forward one more delimiter class run
|
||||
pos = _GetDelimiterClassRunEnd(pos, wordDelimiters, includeWhitespace);
|
||||
if (pos >= limit)
|
||||
{
|
||||
return limit;
|
||||
}
|
||||
else if (!includeWhitespace || pos.x == bufferSize.RightExclusive())
|
||||
pos = _GetDelimiterClassRunEnd(pos, wordDelimiters);
|
||||
if (!includeWhitespace || pos.x == bufferSize.RightExclusive())
|
||||
{
|
||||
// Special case:
|
||||
// we're at the right boundary (and end of a delimiter class run),
|
||||
@@ -1281,8 +1235,7 @@ til::point TextBuffer::GetWordEnd(til::point pos, const std::wstring_view wordDe
|
||||
if (const auto nextDelimClass = bufferSize.IsInBounds(pos) ? _GetDelimiterClassAt(pos, wordDelimiters) : DelimiterClass::ControlChar;
|
||||
nextDelimClass == DelimiterClass::ControlChar)
|
||||
{
|
||||
pos = _GetDelimiterClassRunEnd(pos, wordDelimiters, includeWhitespace);
|
||||
return std::min(pos, limit);
|
||||
return _GetDelimiterClassRunEnd(pos, wordDelimiters);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
@@ -1335,48 +1288,29 @@ bool TextBuffer::IsWordBoundary(const til::point pos, const std::wstring_view wo
|
||||
return prevDelimiterClass != currentDelimiterClass && currentDelimiterClass != DelimiterClass::ControlChar;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the start position for the current delimiter class run, scanning backward
|
||||
// - Stops when the delimiter class changes or a row boundary is reached
|
||||
// - When accessibilityMode is true, freely crosses non-wrapped row boundaries
|
||||
// - When accessibilityMode is false, only crosses wrap-forced row boundaries
|
||||
// Arguments:
|
||||
// - pos - the buffer position to start scanning from
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// - accessibilityMode - when true, cross non-wrapped row boundaries freely
|
||||
// Return Value:
|
||||
// - The position of the first character in the current delimiter class run (inclusive)
|
||||
til::point TextBuffer::_GetDelimiterClassRunStart(til::point pos, const std::wstring_view wordDelimiters, const bool accessibilityMode) const
|
||||
til::point TextBuffer::_GetDelimiterClassRunStart(til::point pos, const std::wstring_view wordDelimiters) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
const auto initialDelimClass = bufferSize.IsInBounds(pos) ? _GetDelimiterClassAt(pos, wordDelimiters) : DelimiterClass::ControlChar;
|
||||
auto nextPos = pos;
|
||||
while (nextPos != bufferSize.Origin())
|
||||
for (auto nextPos = pos; nextPos != bufferSize.Origin(); pos = nextPos)
|
||||
{
|
||||
bufferSize.DecrementInExclusiveBounds(nextPos);
|
||||
|
||||
if (nextPos.x == bufferSize.RightExclusive())
|
||||
{
|
||||
// wrapped onto previous line
|
||||
// wrapped onto previous line,
|
||||
// check if it was forced to wrap
|
||||
const auto& row = GetRowByOffset(nextPos.y);
|
||||
if (!row.WasWrapForced() && !accessibilityMode)
|
||||
if (!row.WasWrapForced())
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
// In accessibility mode (or if row was wrap-forced), continue
|
||||
// across the row boundary. The actual last character of the
|
||||
// previous row will be checked on the next iteration.
|
||||
// Don't update pos to avoid storing a transient position
|
||||
}
|
||||
else if (_GetDelimiterClassAt(nextPos, wordDelimiters) != initialDelimClass)
|
||||
{
|
||||
// if we changed delim class, we're done (don't apply move)
|
||||
return pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = nextPos;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
@@ -1386,8 +1320,7 @@ til::point TextBuffer::_GetDelimiterClassRunStart(til::point pos, const std::wst
|
||||
// Arguments:
|
||||
// - pos - the buffer position being within the current delimiter class
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// - accessibilityMode - when true, cross non-wrapped row boundaries freely
|
||||
til::point TextBuffer::_GetDelimiterClassRunEnd(til::point pos, const std::wstring_view wordDelimiters, const bool accessibilityMode) const
|
||||
til::point TextBuffer::_GetDelimiterClassRunEnd(til::point pos, const std::wstring_view wordDelimiters) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
const auto initialDelimClass = bufferSize.IsInBounds(pos) ? _GetDelimiterClassAt(pos, wordDelimiters) : DelimiterClass::ControlChar;
|
||||
@@ -1400,16 +1333,7 @@ til::point TextBuffer::_GetDelimiterClassRunEnd(til::point pos, const std::wstri
|
||||
// wrapped onto next line,
|
||||
// check if it was forced to wrap or switched delimiter class
|
||||
const auto& row = GetRowByOffset(pos.y);
|
||||
if (accessibilityMode)
|
||||
{
|
||||
// In accessibility mode, always cross row boundaries,
|
||||
// but still stop if the delimiter class changes
|
||||
if (_GetDelimiterClassAt(nextPos, wordDelimiters) != initialDelimClass)
|
||||
{
|
||||
return nextPos;
|
||||
}
|
||||
}
|
||||
else if (!row.WasWrapForced() || _GetDelimiterClassAt(nextPos, wordDelimiters) != initialDelimClass)
|
||||
if (!row.WasWrapForced() || _GetDelimiterClassAt(nextPos, wordDelimiters) != initialDelimClass)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
@@ -1424,6 +1348,283 @@ til::point TextBuffer::_GetDelimiterClassRunEnd(til::point pos, const std::wstri
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the til::point for the beginning of the word you are on
|
||||
// Arguments:
|
||||
// - target - a til::point on the word you are currently on
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// - accessibilityMode - when enabled, we continue expanding left until we are at the beginning of a readable word.
|
||||
// Otherwise, expand left until a character of a new delimiter class is found
|
||||
// (or a row boundary is encountered)
|
||||
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
|
||||
// Return Value:
|
||||
// - The til::point for the first character on the "word" (inclusive)
|
||||
til::point TextBuffer::GetWordStart(const til::point target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
// Consider a buffer with this text in it:
|
||||
// " word other "
|
||||
// In selection (accessibilityMode = false),
|
||||
// a "word" is defined as the range between two delimiters
|
||||
// so the words in the example include [" ", "word", " ", "other", " "]
|
||||
// In accessibility (accessibilityMode = true),
|
||||
// a "word" includes the delimiters after a range of readable characters
|
||||
// so the words in the example include ["word ", "other "]
|
||||
// NOTE: the start anchor (this one) is inclusive, whereas the end anchor (GetWordEnd) is exclusive
|
||||
|
||||
#pragma warning(suppress : 26496)
|
||||
auto copy{ target };
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
if (target == bufferSize.Origin())
|
||||
{
|
||||
// can't expand left
|
||||
return target;
|
||||
}
|
||||
else if (target == bufferSize.EndExclusive())
|
||||
{
|
||||
// GH#7664: Treat EndExclusive as EndInclusive so
|
||||
// that it actually points to a space in the buffer
|
||||
copy = bufferSize.BottomRightInclusive();
|
||||
}
|
||||
else if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
// if at/past the limit --> clamp to limit
|
||||
copy = limitOptional.value_or(bufferSize.BottomRightInclusive());
|
||||
}
|
||||
|
||||
if (accessibilityMode)
|
||||
{
|
||||
return _GetWordStartForAccessibility(copy, wordDelimiters);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _GetWordStartForSelection(copy, wordDelimiters);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper method for GetWordStart(). Get the til::point for the beginning of the word (accessibility definition) you are on
|
||||
// Arguments:
|
||||
// - target - a til::point on the word you are currently on
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The til::point for the first character on the current/previous READABLE "word" (inclusive)
|
||||
til::point TextBuffer::_GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const
|
||||
{
|
||||
auto result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
|
||||
// ignore left boundary. Continue until readable text found
|
||||
while (_GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
|
||||
{
|
||||
if (result == bufferSize.Origin())
|
||||
{
|
||||
//looped around and hit origin (no word between origin and target)
|
||||
return result;
|
||||
}
|
||||
bufferSize.DecrementInBounds(result);
|
||||
}
|
||||
|
||||
// make sure we expand to the left boundary or the beginning of the word
|
||||
while (_GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
|
||||
{
|
||||
if (result == bufferSize.Origin())
|
||||
{
|
||||
// first char in buffer is a RegularChar
|
||||
// we can't move any further back
|
||||
return result;
|
||||
}
|
||||
bufferSize.DecrementInBounds(result);
|
||||
}
|
||||
|
||||
// move off of delimiter
|
||||
bufferSize.IncrementInBounds(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper method for GetWordStart(). Get the til::point for the beginning of the word (selection definition) you are on
|
||||
// Arguments:
|
||||
// - target - a til::point on the word you are currently on
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The til::point for the first character on the current word or delimiter run (stopped by the left margin)
|
||||
til::point TextBuffer::_GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const
|
||||
{
|
||||
auto result = target;
|
||||
const auto bufferSize = GetSize();
|
||||
|
||||
const auto initialDelimiter = _GetDelimiterClassAt(result, wordDelimiters);
|
||||
const bool isControlChar = initialDelimiter == DelimiterClass::ControlChar;
|
||||
|
||||
// expand left until we hit the left boundary or a different delimiter class
|
||||
while (result != bufferSize.Origin() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
|
||||
{
|
||||
if (result.x == bufferSize.Left())
|
||||
{
|
||||
// Prevent wrapping to the previous line if the selection begins on whitespace
|
||||
if (isControlChar)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (result.y > 0)
|
||||
{
|
||||
// Prevent wrapping to the previous line if it was hard-wrapped (e.g. not forced by us to wrap)
|
||||
const auto& priorRow = GetRowByOffset(result.y - 1);
|
||||
if (!priorRow.WasWrapForced())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bufferSize.DecrementInBounds(result);
|
||||
}
|
||||
|
||||
if (_GetDelimiterClassAt(result, wordDelimiters) != initialDelimiter)
|
||||
{
|
||||
// move off of delimiter
|
||||
bufferSize.IncrementInBounds(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Get the til::point for the beginning of the NEXT word
|
||||
// Arguments:
|
||||
// - target - a til::point on the word you are currently on
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// - accessibilityMode - when enabled, we continue expanding right until we are at the beginning of the next READABLE word
|
||||
// Otherwise, expand right until a character of a new delimiter class is found
|
||||
// (or a row boundary is encountered)
|
||||
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
|
||||
// Return Value:
|
||||
// - The til::point for the last character on the "word" (inclusive)
|
||||
til::point TextBuffer::GetWordEnd(const til::point target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
// Consider a buffer with this text in it:
|
||||
// " word other "
|
||||
// In selection (accessibilityMode = false),
|
||||
// a "word" is defined as the range between two delimiters
|
||||
// so the words in the example include [" ", "word", " ", "other", " "]
|
||||
// In accessibility (accessibilityMode = true),
|
||||
// a "word" includes the delimiters after a range of readable characters
|
||||
// so the words in the example include ["word ", "other "]
|
||||
// NOTE: the end anchor (this one) is exclusive, whereas the start anchor (GetWordStart) is inclusive
|
||||
|
||||
// Already at/past the limit. Can't move forward.
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
if (accessibilityMode)
|
||||
{
|
||||
return _GetWordEndForAccessibility(target, wordDelimiters, limit);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _GetWordEndForSelection(target, wordDelimiters);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper method for GetWordEnd(). Get the til::point for the beginning of the next READABLE word
|
||||
// Arguments:
|
||||
// - target - a til::point on the word you are currently on
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// - limit - the last "valid" position in the text buffer (to improve performance)
|
||||
// Return Value:
|
||||
// - The til::point for the first character of the next readable "word". If no next word, return one past the end of the buffer
|
||||
til::point TextBuffer::_GetWordEndForAccessibility(const til::point target, const std::wstring_view wordDelimiters, const til::point limit) const
|
||||
{
|
||||
const auto bufferSize{ GetSize() };
|
||||
auto result{ target };
|
||||
|
||||
if (bufferSize.CompareInBounds(target, limit, true) >= 0)
|
||||
{
|
||||
// if we're already on/past the last RegularChar,
|
||||
// clamp result to that position
|
||||
result = limit;
|
||||
|
||||
// make the result exclusive
|
||||
bufferSize.IncrementInBounds(result, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (result != limit && result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar)
|
||||
{
|
||||
// Iterate through readable text
|
||||
bufferSize.IncrementInBounds(result);
|
||||
}
|
||||
|
||||
while (result != limit && result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar)
|
||||
{
|
||||
// expand to the beginning of the NEXT word
|
||||
bufferSize.IncrementInBounds(result);
|
||||
}
|
||||
|
||||
// Special case: we tried to move one past the end of the buffer
|
||||
// Manually increment onto the EndExclusive point.
|
||||
if (result == bufferSize.BottomRightInclusive())
|
||||
{
|
||||
bufferSize.IncrementInBounds(result, true);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper method for GetWordEnd(). Get the til::point for the beginning of the NEXT word
|
||||
// Arguments:
|
||||
// - target - a til::point on the word you are currently on
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - The til::point for the last character of the current word or delimiter run (stopped by right margin)
|
||||
til::point TextBuffer::_GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const
|
||||
{
|
||||
const auto bufferSize = GetSize();
|
||||
|
||||
auto result = target;
|
||||
const auto initialDelimiter = _GetDelimiterClassAt(result, wordDelimiters);
|
||||
const bool isControlChar = initialDelimiter == DelimiterClass::ControlChar;
|
||||
|
||||
// expand right until we hit the right boundary as a ControlChar or a different delimiter class
|
||||
while (result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
|
||||
{
|
||||
if (result.x == bufferSize.RightInclusive())
|
||||
{
|
||||
// Prevent wrapping to the next line if the selection begins on whitespace
|
||||
if (isControlChar)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Prevent wrapping to the next line if this one was hard-wrapped (e.g. not forced by us to wrap)
|
||||
const auto& row = GetRowByOffset(result.y);
|
||||
if (!row.WasWrapForced())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bufferSize.IncrementInBounds(result);
|
||||
}
|
||||
|
||||
if (_GetDelimiterClassAt(result, wordDelimiters) != initialDelimiter)
|
||||
{
|
||||
// move off of delimiter
|
||||
bufferSize.DecrementInBounds(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextBuffer::_PruneHyperlinks()
|
||||
{
|
||||
// Check the old first row for hyperlink references
|
||||
@@ -1470,6 +1671,57 @@ void TextBuffer::_PruneHyperlinks()
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update pos to be the position of the first character of the next word. This is used for accessibility
|
||||
// Arguments:
|
||||
// - pos - a til::point on the word you are currently on
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
|
||||
// Return Value:
|
||||
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
|
||||
// - pos - The til::point for the first character on the "word" (inclusive)
|
||||
bool TextBuffer::MoveToNextWord(til::point& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional) const
|
||||
{
|
||||
// move to the beginning of the next word
|
||||
// NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word"
|
||||
// This is also the inclusive start of the next word.
|
||||
const auto bufferSize{ GetSize() };
|
||||
const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) };
|
||||
const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) };
|
||||
|
||||
if (bufferSize.CompareInBounds(copy, limit, true) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pos = copy;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update pos to be the position of the first character of the previous word. This is used for accessibility
|
||||
// Arguments:
|
||||
// - pos - a til::point on the word you are currently on
|
||||
// - wordDelimiters - what characters are we considering for the separation of words
|
||||
// Return Value:
|
||||
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
|
||||
// - pos - The til::point for the first character on the "word" (inclusive)
|
||||
bool TextBuffer::MoveToPreviousWord(til::point& pos, std::wstring_view wordDelimiters) const
|
||||
{
|
||||
// move to the beginning of the current word
|
||||
auto copy{ GetWordStart(pos, wordDelimiters, true) };
|
||||
|
||||
if (!GetSize().DecrementInBounds(copy, true))
|
||||
{
|
||||
// can't move behind current word
|
||||
return false;
|
||||
}
|
||||
|
||||
// move to the beginning of the previous word
|
||||
pos = GetWordStart(copy, wordDelimiters, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Update pos to be the beginning of the current glyph/character. This is used for accessibility
|
||||
// Arguments:
|
||||
@@ -3527,34 +3779,3 @@ void TextBuffer::ManuallyMarkRowAsPrompt(til::CoordType y)
|
||||
attr.SetMarkAttributes(MarkKind::Prompt);
|
||||
}
|
||||
}
|
||||
|
||||
// This is an optimization used by the renderer to avoid scheduling a timer if not necessary;
|
||||
// unlike the renderer, we know the committed range of our own buffer.
|
||||
bool TextBuffer::ContainsBlinkAttributeInRegion(const Microsoft::Console::Types::Viewport& region) const
|
||||
{
|
||||
const auto top = region.Top();
|
||||
auto bottom = std::min(region.BottomInclusive(), _estimateOffsetOfLastCommittedRow());
|
||||
|
||||
for (auto row = top; row < bottom; ++row)
|
||||
{
|
||||
const auto& r = GetRowByOffset(row);
|
||||
for (const auto& attr : r.Attributes())
|
||||
{
|
||||
if (attr.IsBlinking())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TextBuffer::IsGlyphDoubleWidthAt(const til::point at) const
|
||||
{
|
||||
if (!_isRowCommitted(at.y)) [[unlikely]]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _getRow(at.y).DbcsAttrAt(at.x) != DbcsAttribute::Single;
|
||||
}
|
||||
|
||||
@@ -172,10 +172,15 @@ public:
|
||||
void TriggerNewTextNotification(const std::wstring_view newText);
|
||||
void TriggerSelection();
|
||||
|
||||
til::point GetWordStart(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
til::point GetWordEnd(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
til::point GetWordStart(const til::point target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
til::point GetWordEnd(const til::point target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
|
||||
til::point GetWordStart2(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
til::point GetWordEnd2(til::point pos, const std::wstring_view wordDelimiters, bool includeWhitespace, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
|
||||
bool IsWordBoundary(const til::point pos, const std::wstring_view wordDelimiters) const;
|
||||
bool MoveToNextWord(til::point& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
bool MoveToPreviousWord(til::point& pos, const std::wstring_view wordDelimiters) const;
|
||||
|
||||
til::point GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
til::point GetGlyphEnd(const til::point pos, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
|
||||
@@ -310,9 +315,6 @@ public:
|
||||
void SetScrollbarData(ScrollbarData mark, til::CoordType y);
|
||||
void ManuallyMarkRowAsPrompt(til::CoordType y);
|
||||
|
||||
bool ContainsBlinkAttributeInRegion(const Microsoft::Console::Types::Viewport& region) const;
|
||||
bool IsGlyphDoubleWidthAt(const til::point at) const;
|
||||
|
||||
private:
|
||||
void _reserve(til::size screenBufferSize, const TextAttribute& defaultAttributes);
|
||||
void _commit(const std::byte* row);
|
||||
@@ -322,13 +324,16 @@ private:
|
||||
ROW& _getRowByOffsetDirect(size_t offset);
|
||||
ROW& _getRow(til::CoordType y) const;
|
||||
til::CoordType _estimateOffsetOfLastCommittedRow() const noexcept;
|
||||
bool _isRowCommitted(til::CoordType y) const noexcept;
|
||||
|
||||
void _SetFirstRowIndex(const til::CoordType FirstRowIndex) noexcept;
|
||||
void _ExpandTextRow(til::inclusive_rect& selectionRow) const;
|
||||
DelimiterClass _GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetDelimiterClassRunStart(til::point pos, const std::wstring_view wordDelimiters, const bool accessibilityMode = false) const;
|
||||
til::point _GetDelimiterClassRunEnd(til::point pos, const std::wstring_view wordDelimiters, const bool accessibilityMode = false) const;
|
||||
til::point _GetDelimiterClassRunStart(til::point pos, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetDelimiterClassRunEnd(til::point pos, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetWordStartForAccessibility(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetWordStartForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
til::point _GetWordEndForAccessibility(const til::point target, const std::wstring_view wordDelimiters, const til::point limit) const;
|
||||
til::point _GetWordEndForSelection(const til::point target, const std::wstring_view wordDelimiters) const;
|
||||
void _PruneHyperlinks();
|
||||
|
||||
std::wstring _commandForRow(const til::CoordType rowOffset, const til::CoordType bottomInclusive, const bool clipAtCursor = false) const;
|
||||
|
||||
@@ -34,16 +34,6 @@ class UTextAdapterTests
|
||||
{
|
||||
TEST_CLASS(UTextAdapterTests);
|
||||
|
||||
TEST_CLASS_SETUP(ClassSetup)
|
||||
{
|
||||
wil::unique_hmodule icu{ LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) };
|
||||
if (!icu)
|
||||
{
|
||||
WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped, L"ICU is not present");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_METHOD(Unicode)
|
||||
{
|
||||
DummyRenderer renderer;
|
||||
|
||||
@@ -26,9 +26,6 @@ TARGETLIBS = \
|
||||
$(CONSOLE_OBJ_PATH)\types\lib\$(O)\ConTypes.lib \
|
||||
$(TARGETLIBS) \
|
||||
|
||||
DELAYLOAD = \
|
||||
icu.dll \
|
||||
|
||||
# -------------------------------------
|
||||
# Localization
|
||||
# -------------------------------------
|
||||
|
||||
@@ -237,6 +237,7 @@
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="unvirtualizedResources" />
|
||||
<rescap:Capability Name="appLicensing" />
|
||||
</Capabilities>
|
||||
|
||||
<Extensions>
|
||||
|
||||
@@ -237,6 +237,7 @@
|
||||
<Capability Name="internetClient" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="unvirtualizedResources" />
|
||||
<rescap:Capability Name="appLicensing" />
|
||||
</Capabilities>
|
||||
|
||||
<Extensions>
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
ResourceKey="TabViewBackground" />
|
||||
|
||||
<SolidColorBrush x:Key="SettingsUiTabBrush"
|
||||
Color="#282828" />
|
||||
Color="#0c0c0c" />
|
||||
|
||||
<SolidColorBrush x:Key="BroadcastPaneBorderColor"
|
||||
Color="{StaticResource SystemAccentColorDark2}" />
|
||||
@@ -211,7 +211,7 @@
|
||||
ResourceKey="TabViewBackground" />
|
||||
|
||||
<SolidColorBrush x:Key="SettingsUiTabBrush"
|
||||
Color="#F9F9F9" />
|
||||
Color="#ffffff" />
|
||||
|
||||
<SolidColorBrush x:Key="BroadcastPaneBorderColor"
|
||||
Color="{StaticResource SystemAccentColorLight2}" />
|
||||
@@ -234,7 +234,7 @@
|
||||
ResourceKey="SystemColorButtonFaceColorBrush" />
|
||||
|
||||
<StaticResource x:Key="SettingsUiTabBrush"
|
||||
ResourceKey="SystemColorWindowBrush" />
|
||||
ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
|
||||
<SolidColorBrush x:Key="BroadcastPaneBorderColor"
|
||||
Color="{StaticResource SystemColorHighlightColor}" />
|
||||
|
||||
@@ -1475,7 +1475,7 @@ namespace winrt::TerminalApp::implementation
|
||||
WI_IsAnyFlagSet(source, SuggestionsSource::CommandHistory | SuggestionsSource::QuickFixes);
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
{
|
||||
currentWorkingDirectory = control.WorkingDirectory();
|
||||
currentWorkingDirectory = control.CurrentWorkingDirectory();
|
||||
|
||||
if (shouldGetContext)
|
||||
{
|
||||
|
||||
@@ -854,11 +854,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>Der aktive Bereich wurde auf die Registerkarte „{0}“ verschoben</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>Registerkarte „{0}“ wurde in das Fenster „{1}“ verschoben</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Registerkarte „{0}“ in neues Fenster verschoben</value>
|
||||
@@ -870,7 +870,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Der aktive Bereich wurde in das Fenster "{0}" verschoben</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Aktiver Bereich in neues Fenster verschoben</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>Panel activo movido a la pestaña "{0}"</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>La pestaña "{0}" se ha movido a la ventana "{1}"</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>La pestaña "{0}" se ha movido a la nueva ventana</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Panel activo movido a la ventana "{0}"</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Panel activo movido a nueva ventana</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>Volet actif déplacé vers l’onglet « {0} »</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>Onglet « {0} » déplacé vers la fenêtre « {1} »</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Onglet « {0} » déplacé vers une nouvelle fenêtre</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Volet actif déplacé vers l’onglet « {0} »</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Volet actif déplacé vers une nouvelle fenêtre</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>Riquadro attivo spostato nella scheda "{0}"</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>Scheda "{0}" spostata nella finestra "{1}"</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Scheda "{0}" spostata in una nuova finestra</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Riquadro attivo spostato nella finestra "{0}"</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Riquadro attivo spostato in una nuova finestra</value>
|
||||
|
||||
@@ -852,11 +852,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>アクティブなペインを [{0}] タブに移動しました</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>[{0}] タブを "{1}" ウィンドウに移動しました</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>[{0}] タブを新しいウィンドウに移動しました</value>
|
||||
@@ -868,7 +868,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>アクティブなペインを "{0}" ウィンドウに移動しました</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>アクティブなペインを新しいウィンドウに移動しました</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>활성 창이 "{0}" 탭으로 이동됨</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>"{0}" 탭이 "{1}" 창으로 이동됨</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>"{0}" 탭이 새 창으로 이동됨</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>활성 창이 "{0}" 창으로 이동됨</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>활성 창이 새 창으로 이동됨</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>Painel ativo movido para a guia "{0}"</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>Guia "{0}" movida para janela "{1}"</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Guia "{0}" movida para nova janela</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Painel ativo movido para a janela "{0}"</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Painel ativo movido para nova janela</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>∆çťíνĕ рåⁿэ мôνеð ťб "{0}" ţав !!! !!! !!!</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>"{0}" ťāъ мōνęđ τŏ "{1}" шΐπδŏẅ !!! !!! !!!</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>"{0}" тąь mǿνєđ ŧσ ήèώ ẅĩŋďøẃ !!! !!! !!!</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Λςťìνє рáиė mόνéð ťб "{0}" ŵîńđθω !!! !!! !!! </value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Αĉťįνέ ρªņз mσνёđ τǿ ήёẃ ẃîпďǿω !!! !!! !!!</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>∆çťíνĕ рåⁿэ мôνеð ťб "{0}" ţав !!! !!! !!!</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>"{0}" ťāъ мōνęđ τŏ "{1}" шΐπδŏẅ !!! !!! !!!</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>"{0}" тąь mǿνєđ ŧσ ήèώ ẅĩŋďøẃ !!! !!! !!!</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Λςťìνє рáиė mόνéð ťб "{0}" ŵîńđθω !!! !!! !!! </value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Αĉťįνέ ρªņз mσνёđ τǿ ήёẃ ẃîпďǿω !!! !!! !!!</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>∆çťíνĕ рåⁿэ мôνеð ťб "{0}" ţав !!! !!! !!!</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>"{0}" ťāъ мōνęđ τŏ "{1}" шΐπδŏẅ !!! !!! !!!</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>"{0}" тąь mǿνєđ ŧσ ήèώ ẅĩŋďøẃ !!! !!! !!!</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Λςťìνє рáиė mόνéð ťб "{0}" ŵîńđθω !!! !!! !!! </value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Αĉťįνέ ρªņз mσνёđ τǿ ήёẃ ẃîпďǿω !!! !!! !!!</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>Активная область перемещена на вкладку "{0}"</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>Вкладка "{0}" перемещена в окно "{1}"</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Вкладка "{0}" перемещена в новое окно</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>Активная область перемещена в окно "{0}"</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>Активная область перемещена в новое окно</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>活动窗格已移动到“{0}”选项卡</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>“{0}”选项卡已移动到“{1}”窗口</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>“{0}”选项卡已移动到新窗口</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>活动窗格已移动到“{0}”选项卡</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>活动窗格已移动到新窗口</value>
|
||||
|
||||
@@ -851,11 +851,11 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
|
||||
<value>活動窗格已移動至「{0}」索引標籤</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
|
||||
<value>「{0}」索引標籤已移至「{1}」視窗</value>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
|
||||
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window to which the tab was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>「{0}」索引標籤已移至新視窗</value>
|
||||
@@ -867,7 +867,7 @@
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow2" xml:space="preserve">
|
||||
<value>活動窗格已移動至「{0}」視窗</value>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window the pane was moved to.</comment>
|
||||
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the window to which the pane was moved.</comment>
|
||||
</data>
|
||||
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
|
||||
<value>活動窗格已移至新視窗</value>
|
||||
|
||||
@@ -1600,7 +1600,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Replace the Starting directory with the CWD, if given
|
||||
const auto workingDirectory = control.WorkingDirectory();
|
||||
if (Utils::IsValidDirectory(workingDirectory.c_str()))
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
controlSettings.DefaultSettings()->StartingDirectory(workingDirectory);
|
||||
}
|
||||
@@ -3607,7 +3608,8 @@ namespace winrt::TerminalApp::implementation
|
||||
profile = GetClosestProfileForDuplicationOfProfile(profile);
|
||||
controlSettings = Settings::TerminalSettings::CreateWithProfile(_settings, profile);
|
||||
const auto workingDirectory = tabImpl->GetActiveTerminalControl().WorkingDirectory();
|
||||
if (Utils::IsValidDirectory(workingDirectory.c_str()))
|
||||
const auto validWorkingDirectory = !workingDirectory.empty();
|
||||
if (validWorkingDirectory)
|
||||
{
|
||||
controlSettings.DefaultSettings()->StartingDirectory(workingDirectory);
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
args.Profile(::Microsoft::Console::Utils::GuidToString(_profile.Guid()));
|
||||
// If we know the user's working directory use it instead of the profile.
|
||||
if (const auto dir = _control.WorkingDirectory(); ::Microsoft::Console::Utils::IsValidDirectory(dir.c_str()))
|
||||
if (const auto dir = _control.WorkingDirectory(); !dir.empty())
|
||||
{
|
||||
args.StartingDirectory(dir);
|
||||
}
|
||||
|
||||
@@ -2426,6 +2426,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return *context;
|
||||
}
|
||||
|
||||
winrt::hstring ControlCore::CurrentWorkingDirectory() const
|
||||
{
|
||||
return winrt::hstring{ _terminal->GetWorkingDirectory() };
|
||||
}
|
||||
|
||||
bool ControlCore::QuickFixesAvailable() const noexcept
|
||||
{
|
||||
return _cachedQuickFixes && _cachedQuickFixes.Size() > 0;
|
||||
|
||||
@@ -191,6 +191,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ContextMenuSelectCommand();
|
||||
void ContextMenuSelectOutput();
|
||||
|
||||
winrt::hstring CurrentWorkingDirectory() const;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ITerminalInput
|
||||
|
||||
@@ -169,8 +169,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ControlInteractivity::GotFocus()
|
||||
{
|
||||
_focused = true;
|
||||
|
||||
if (_uiaEngine.get())
|
||||
{
|
||||
THROW_IF_FAILED(_uiaEngine->Enable());
|
||||
@@ -183,8 +181,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ControlInteractivity::LostFocus()
|
||||
{
|
||||
_focused = false;
|
||||
|
||||
if (_uiaEngine.get())
|
||||
{
|
||||
THROW_IF_FAILED(_uiaEngine->Disable());
|
||||
@@ -252,8 +248,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
PasteFromClipboard.raise(*this, std::move(args));
|
||||
}
|
||||
|
||||
void ControlInteractivity::PointerPressed(const uint32_t /*pointerId*/,
|
||||
Control::MouseButtonState buttonState,
|
||||
void ControlInteractivity::PointerPressed(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const uint64_t timestamp,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
@@ -266,10 +261,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto shiftEnabled = modifiers.IsShiftPressed();
|
||||
const auto ctrlEnabled = modifiers.IsCtrlPressed();
|
||||
|
||||
// Mark that this pointer event actually started within our bounds.
|
||||
// We'll need this later, for PointerMoved events.
|
||||
_pointerPressedInBounds = true;
|
||||
|
||||
// GH#9396: we prioritize hyper-link over VT mouse events
|
||||
auto hyperlink = _core->GetHyperlink(terminalPosition.to_core_point());
|
||||
if (WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown) &&
|
||||
@@ -309,8 +300,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const auto isOnOriginalPosition = _lastMouseClickPosNoSelection == pixelPosition;
|
||||
|
||||
// Rounded coordinates for text selection.
|
||||
// Don't round in VT mouse mode; cell-level precision matters more
|
||||
const auto round = !_core->IsVtMouseModeEnabled();
|
||||
// Don't round in VT mouse mode; cell-level precision matters more.
|
||||
// Only round for single-click: for double/triple-click, rounding
|
||||
// can push the position to the next cell, selecting the wrong word.
|
||||
const auto round = multiClickMapper == 1 && !_core->IsVtMouseModeEnabled();
|
||||
_core->LeftClickOnTerminal(_getTerminalPosition(til::point{ pixelPosition }, round),
|
||||
multiClickMapper,
|
||||
altEnabled,
|
||||
@@ -364,23 +357,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlInteractivity::TouchPressed(const Core::Point contactPoint)
|
||||
void ControlInteractivity::TouchPressed(const winrt::Windows::Foundation::Point contactPoint)
|
||||
{
|
||||
_touchAnchor = contactPoint;
|
||||
}
|
||||
|
||||
bool ControlInteractivity::PointerMoved(const uint32_t /*pointerId*/,
|
||||
Control::MouseButtonState buttonState,
|
||||
bool ControlInteractivity::PointerMoved(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const Core::Point pixelPosition)
|
||||
const bool focused,
|
||||
const Core::Point pixelPosition,
|
||||
const bool pointerPressedInBounds)
|
||||
{
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, false);
|
||||
// Returning true from this function indicates that the caller should do no further processing of this movement.
|
||||
bool handledCompletely = false;
|
||||
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (_focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
if (focused && !_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
{
|
||||
_sendMouseEventHelper(terminalPosition, pointerUpdateKind, modifiers, 0, buttonState);
|
||||
handledCompletely = true;
|
||||
@@ -389,7 +383,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// actually start _in_ the control bounds. Case in point - someone drags
|
||||
// a file into the bounds of the control. That shouldn't send the
|
||||
// selection into space.
|
||||
else if (_focused && _pointerPressedInBounds && WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown))
|
||||
else if (focused && pointerPressedInBounds && WI_IsFlagSet(buttonState, MouseButtonState::IsLeftButtonDown))
|
||||
{
|
||||
if (_singleClickTouchdownPos)
|
||||
{
|
||||
@@ -435,9 +429,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return handledCompletely;
|
||||
}
|
||||
|
||||
void ControlInteractivity::TouchMoved(const Core::Point newTouchPoint)
|
||||
void ControlInteractivity::TouchMoved(const winrt::Windows::Foundation::Point newTouchPoint,
|
||||
const bool focused)
|
||||
{
|
||||
if (_focused &&
|
||||
if (focused &&
|
||||
_touchAnchor)
|
||||
{
|
||||
const auto anchor = _touchAnchor.value();
|
||||
@@ -471,14 +466,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void ControlInteractivity::PointerReleased(const uint32_t /*pointerId*/,
|
||||
Control::MouseButtonState buttonState,
|
||||
void ControlInteractivity::PointerReleased(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const Core::Point pixelPosition)
|
||||
{
|
||||
_pointerPressedInBounds = false;
|
||||
|
||||
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, false);
|
||||
// Short-circuit isReadOnly check to avoid warning dialog
|
||||
if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
|
||||
|
||||
@@ -51,23 +51,23 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
::Microsoft::Console::Render::IRenderData* GetRenderData() const;
|
||||
|
||||
#pragma region Input Methods
|
||||
void PointerPressed(const uint32_t pointerId,
|
||||
Control::MouseButtonState buttonState,
|
||||
void PointerPressed(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const uint64_t timestamp,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const Core::Point pixelPosition);
|
||||
void TouchPressed(const Core::Point contactPoint);
|
||||
void TouchPressed(const winrt::Windows::Foundation::Point contactPoint);
|
||||
|
||||
bool PointerMoved(const uint32_t pointerId,
|
||||
Control::MouseButtonState buttonState,
|
||||
bool PointerMoved(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const Core::Point pixelPosition);
|
||||
void TouchMoved(const Core::Point newTouchPoint);
|
||||
const bool focused,
|
||||
const Core::Point pixelPosition,
|
||||
const bool pointerPressedInBounds);
|
||||
void TouchMoved(const winrt::Windows::Foundation::Point newTouchPoint,
|
||||
const bool focused);
|
||||
|
||||
void PointerReleased(const uint32_t pointerId,
|
||||
Control::MouseButtonState buttonState,
|
||||
void PointerReleased(Control::MouseButtonState buttonState,
|
||||
const unsigned int pointerUpdateKind,
|
||||
const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
|
||||
const Core::Point pixelPosition);
|
||||
@@ -115,7 +115,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
// If this is set, then we assume we are in the middle of panning the
|
||||
// viewport via touch input.
|
||||
std::optional<Core::Point> _touchAnchor;
|
||||
std::optional<winrt::Windows::Foundation::Point> _touchAnchor;
|
||||
|
||||
using Timestamp = uint64_t;
|
||||
|
||||
@@ -142,9 +142,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
uint64_t _id;
|
||||
static std::atomic<uint64_t> _nextId;
|
||||
|
||||
bool _focused{ false };
|
||||
bool _pointerPressedInBounds{ false };
|
||||
|
||||
unsigned int _numberOfClicks(Core::Point clickPos, Timestamp clickTime);
|
||||
void _updateSystemParameterSettings() noexcept;
|
||||
|
||||
|
||||
@@ -36,24 +36,24 @@ namespace Microsoft.Terminal.Control
|
||||
void RequestPasteTextFromClipboard();
|
||||
void SetEndSelectionPoint(Microsoft.Terminal.Core.Point point);
|
||||
|
||||
void PointerPressed(UInt32 pointerId,
|
||||
MouseButtonState buttonState,
|
||||
void PointerPressed(MouseButtonState buttonState,
|
||||
UInt32 pointerUpdateKind,
|
||||
UInt64 timestamp,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Microsoft.Terminal.Core.Point pixelPosition);
|
||||
void TouchPressed(Microsoft.Terminal.Core.Point contactPoint);
|
||||
void TouchPressed(Windows.Foundation.Point contactPoint);
|
||||
|
||||
Boolean PointerMoved(UInt32 pointerId,
|
||||
MouseButtonState buttonState,
|
||||
Boolean PointerMoved(MouseButtonState buttonState,
|
||||
UInt32 pointerUpdateKind,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Microsoft.Terminal.Core.Point pixelPosition);
|
||||
Boolean focused,
|
||||
Microsoft.Terminal.Core.Point pixelPosition,
|
||||
Boolean pointerPressedInBounds);
|
||||
|
||||
void TouchMoved(Microsoft.Terminal.Core.Point newTouchPoint);
|
||||
void TouchMoved(Windows.Foundation.Point newTouchPoint,
|
||||
Boolean focused);
|
||||
|
||||
void PointerReleased(UInt32 pointerId,
|
||||
MouseButtonState buttonState,
|
||||
void PointerReleased(MouseButtonState buttonState,
|
||||
UInt32 pointerUpdateKind,
|
||||
Microsoft.Terminal.Core.ControlKeyStates modifiers,
|
||||
Microsoft.Terminal.Core.Point pixelPosition);
|
||||
|
||||
@@ -76,7 +76,6 @@ namespace Microsoft.Terminal.Control
|
||||
Boolean RepositionCursorWithMouse { get; };
|
||||
|
||||
PathTranslationStyle PathTranslationStyle { get; };
|
||||
String DragDropDelimiter { get; };
|
||||
|
||||
// NOTE! When adding something here, make sure to update ControlProperties.h too!
|
||||
};
|
||||
|
||||
@@ -60,5 +60,7 @@ namespace Microsoft.Terminal.Control
|
||||
void SelectOutput(Boolean goUp);
|
||||
IVector<ScrollMark> ScrollMarks { get; };
|
||||
|
||||
String CurrentWorkingDirectory { get; };
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1988,14 +1988,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// NB: I don't think this is correct because the touch should be in the center of the rect.
|
||||
// I suspect the point.Position() would be correct.
|
||||
const auto contactRect = point.Properties().ContactRect();
|
||||
til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y };
|
||||
_interactivity.TouchPressed(newTouchPoint.to_core_point());
|
||||
_interactivity.TouchPressed({ contactRect.X, contactRect.Y });
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto cursorPosition = point.Position();
|
||||
_interactivity.PointerPressed(point.PointerId(),
|
||||
TermControl::GetPressedMouseButtons(point),
|
||||
_interactivity.PointerPressed(TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
point.Timestamp(),
|
||||
ControlKeyStates{ args.KeyModifiers() },
|
||||
@@ -2034,11 +2032,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (type == Windows::Devices::Input::PointerDeviceType::Mouse ||
|
||||
type == Windows::Devices::Input::PointerDeviceType::Pen)
|
||||
{
|
||||
auto suppressFurtherHandling = _interactivity.PointerMoved(point.PointerId(),
|
||||
TermControl::GetPressedMouseButtons(point),
|
||||
auto suppressFurtherHandling = _interactivity.PointerMoved(TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
ControlKeyStates(args.KeyModifiers()),
|
||||
pixelPosition);
|
||||
_focused,
|
||||
pixelPosition,
|
||||
_pointerPressedInBounds);
|
||||
|
||||
// GH#9109 - Only start an auto-scroll when the drag actually
|
||||
// started within our bounds. Otherwise, someone could start a drag
|
||||
@@ -2077,9 +2076,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
else if (type == Windows::Devices::Input::PointerDeviceType::Touch)
|
||||
{
|
||||
const auto contactRect = point.Properties().ContactRect();
|
||||
til::point newTouchPoint{ til::math::rounding, contactRect.X, contactRect.Y };
|
||||
|
||||
_interactivity.TouchMoved(newTouchPoint.to_core_point());
|
||||
_interactivity.TouchMoved({ contactRect.X, contactRect.Y }, _focused);
|
||||
}
|
||||
|
||||
args.Handled(true);
|
||||
@@ -2112,8 +2109,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
if (type == Windows::Devices::Input::PointerDeviceType::Mouse ||
|
||||
type == Windows::Devices::Input::PointerDeviceType::Pen)
|
||||
{
|
||||
_interactivity.PointerReleased(point.PointerId(),
|
||||
TermControl::GetPressedMouseButtons(point),
|
||||
_interactivity.PointerReleased(TermControl::GetPressedMouseButtons(point),
|
||||
TermControl::GetPointerUpdateKind(point),
|
||||
ControlKeyStates(args.KeyModifiers()),
|
||||
pixelPosition);
|
||||
@@ -3077,7 +3073,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// the full path of the file to our terminal connection. Like conhost, if
|
||||
// the path contains a space, we'll wrap the path in quotes.
|
||||
// - Unlike conhost, if multiple files are dropped onto the terminal, we'll
|
||||
// write all the paths to the terminal, separated by the configured delimiter.
|
||||
// write all the paths to the terminal, separated by spaces.
|
||||
// Arguments:
|
||||
// - e: The DragEventArgs from the Drop event
|
||||
// Return Value:
|
||||
@@ -3198,13 +3194,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
}
|
||||
|
||||
std::wstring allPathsString;
|
||||
const auto delimiter{ _core.Settings().DragDropDelimiter() };
|
||||
for (auto& fullPath : fullPaths)
|
||||
{
|
||||
// Join the paths with the delimiter
|
||||
// Join the paths with spaces
|
||||
if (!allPathsString.empty())
|
||||
{
|
||||
allPathsString += delimiter;
|
||||
allPathsString += L" ";
|
||||
}
|
||||
|
||||
const auto translationStyle{ _core.Settings().PathTranslationStyle() };
|
||||
@@ -3736,6 +3731,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
return _core.CommandHistory();
|
||||
}
|
||||
winrt::hstring TermControl::CurrentWorkingDirectory() const
|
||||
{
|
||||
return _core.CurrentWorkingDirectory();
|
||||
}
|
||||
|
||||
void TermControl::UpdateWinGetSuggestions(Windows::Foundation::Collections::IVector<hstring> suggestions)
|
||||
{
|
||||
|
||||
@@ -117,6 +117,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void ScrollToMark(const Control::ScrollToMarkDirection& direction);
|
||||
void SelectCommand(const bool goUp);
|
||||
void SelectOutput(const bool goUp);
|
||||
|
||||
winrt::hstring CurrentWorkingDirectory() const;
|
||||
#pragma endregion
|
||||
|
||||
void ScrollViewport(int viewTop);
|
||||
|
||||
@@ -313,7 +313,7 @@ std::pair<til::point, til::point> Terminal::_ExpandSelectionAnchors(std::pair<ti
|
||||
break;
|
||||
case SelectionExpansion::Word:
|
||||
{
|
||||
start = buffer.GetWordStart(start, _wordDelimiters, false);
|
||||
start = buffer.GetWordStart2(start, _wordDelimiters, false);
|
||||
|
||||
// GH#5099: We round to the nearest cell boundary,
|
||||
// so we would normally prematurely expand to the next word
|
||||
@@ -325,7 +325,7 @@ std::pair<til::point, til::point> Terminal::_ExpandSelectionAnchors(std::pair<ti
|
||||
{
|
||||
bufferSize.DecrementInExclusiveBounds(end);
|
||||
}
|
||||
end = buffer.GetWordEnd(end, _wordDelimiters, false);
|
||||
end = buffer.GetWordEnd2(end, _wordDelimiters, false);
|
||||
break;
|
||||
}
|
||||
case SelectionExpansion::Char:
|
||||
@@ -435,9 +435,9 @@ void Terminal::ExpandSelectionToWord()
|
||||
const auto& buffer = _activeBuffer();
|
||||
auto selection{ _selection.write() };
|
||||
wil::hide_name _selection;
|
||||
selection->start = buffer.GetWordStart(selection->start, _wordDelimiters, false);
|
||||
selection->start = buffer.GetWordStart2(selection->start, _wordDelimiters, false);
|
||||
selection->pivot = selection->start;
|
||||
selection->end = buffer.GetWordEnd(selection->end, _wordDelimiters, false);
|
||||
selection->end = buffer.GetWordEnd2(selection->end, _wordDelimiters, false);
|
||||
|
||||
// if we're targeting both endpoints, instead just target "end"
|
||||
if (WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::Start) && WI_IsFlagSet(_selectionEndpoint, SelectionEndpoint::End))
|
||||
@@ -826,13 +826,13 @@ void Terminal::_MoveByWord(SelectionDirection direction, til::point& pos)
|
||||
case SelectionDirection::Left:
|
||||
{
|
||||
auto nextPos = pos;
|
||||
nextPos = buffer.GetWordStart(nextPos, _wordDelimiters, true);
|
||||
nextPos = buffer.GetWordStart2(nextPos, _wordDelimiters, true);
|
||||
if (nextPos == pos)
|
||||
{
|
||||
// didn't move because we're already at the beginning of a word,
|
||||
// so move to the beginning of the previous word
|
||||
buffer.GetSize().DecrementInExclusiveBounds(nextPos);
|
||||
nextPos = buffer.GetWordStart(nextPos, _wordDelimiters, true);
|
||||
nextPos = buffer.GetWordStart2(nextPos, _wordDelimiters, true);
|
||||
}
|
||||
pos = nextPos;
|
||||
break;
|
||||
@@ -841,24 +841,24 @@ void Terminal::_MoveByWord(SelectionDirection direction, til::point& pos)
|
||||
{
|
||||
const auto mutableViewportEndExclusive = _GetMutableViewport().BottomInclusiveRightExclusive();
|
||||
auto nextPos = pos;
|
||||
nextPos = buffer.GetWordEnd(nextPos, _wordDelimiters, true, mutableViewportEndExclusive);
|
||||
nextPos = buffer.GetWordEnd2(nextPos, _wordDelimiters, true, mutableViewportEndExclusive);
|
||||
if (nextPos == pos)
|
||||
{
|
||||
// didn't move because we're already at the end of a word,
|
||||
// so move to the end of the next word
|
||||
buffer.GetSize().IncrementInExclusiveBounds(nextPos);
|
||||
nextPos = buffer.GetWordEnd(nextPos, _wordDelimiters, true, mutableViewportEndExclusive);
|
||||
nextPos = buffer.GetWordEnd2(nextPos, _wordDelimiters, true, mutableViewportEndExclusive);
|
||||
}
|
||||
pos = nextPos;
|
||||
break;
|
||||
}
|
||||
case SelectionDirection::Up:
|
||||
_MoveByChar(direction, pos);
|
||||
pos = buffer.GetWordStart(pos, _wordDelimiters, true);
|
||||
pos = buffer.GetWordStart2(pos, _wordDelimiters, true);
|
||||
break;
|
||||
case SelectionDirection::Down:
|
||||
_MoveByChar(direction, pos);
|
||||
pos = buffer.GetWordEnd(pos, _wordDelimiters, true);
|
||||
pos = buffer.GetWordEnd2(pos, _wordDelimiters, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +353,6 @@ namespace winrt::Microsoft::Terminal::Settings
|
||||
_AllowVtChecksumReport = profile.AllowVtChecksumReport();
|
||||
_AllowVtClipboardWrite = profile.AllowVtClipboardWrite();
|
||||
_PathTranslationStyle = profile.PathTranslationStyle();
|
||||
_DragDropDelimiter = profile.DragDropDelimiter();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -145,7 +145,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AnswerbackMessage);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, RainbowSuggestions);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, PathTranslationStyle);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, DragDropDelimiter);
|
||||
|
||||
WINRT_PROPERTY(bool, IsBaseLayer, false);
|
||||
WINRT_PROPERTY(bool, FocusDeleteButton, false);
|
||||
|
||||
@@ -139,7 +139,6 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, AnswerbackMessage);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, RainbowSuggestions);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.PathTranslationStyle, PathTranslationStyle);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, DragDropDelimiter);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,16 +272,6 @@
|
||||
Style="{StaticResource ComboBoxSettingStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Drag Drop Delimiter -->
|
||||
<local:SettingContainer x:Name="DragDropDelimiter"
|
||||
x:Uid="Profile_DragDropDelimiter"
|
||||
ClearSettingValue="{x:Bind Profile.ClearDragDropDelimiter}"
|
||||
HasSettingValue="{x:Bind Profile.HasDragDropDelimiter, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.DragDropDelimiterOverrideSource, Mode=OneWay}">
|
||||
<TextBox Style="{StaticResource TextBoxSettingStyle}"
|
||||
Text="{x:Bind Profile.DragDropDelimiter, Mode=TwoWay}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Titelleiste ausblenden (Neustart erforderlich)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Wenn diese Option deaktiviert ist, wird die Titelleiste über den Registerkarten angezeigt.</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Startverzeichnis</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Startverzeichnis</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Startverzeichnis</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>Das Verzeichnis, in dem das Profil gestartet wird, wenn es geladen wird.</value>
|
||||
@@ -1742,7 +1742,7 @@
|
||||
<comment>A supplementary setting to the "font face" setting. Toggling this control updates the font face control to show all of the fonts installed.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFaceShowAllFonts.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Wenn diese Option aktiviert ist, werden alle installierten Schriftarten in der Liste oben angezeigt. Andernfalls wird nur die Liste der Festbreitenschriftarten angezeigt.</value>
|
||||
<value>Wenn diese Option aktiviert ist, werden alle installierten Schriftarten in der Liste oben angezeigt. Andernfalls wird nur die Liste der Schriftarten mit fester Breite angezeigt.</value>
|
||||
<comment>A description for what the supplementary "show all fonts" setting does. Presented near "Profile_FontFaceShowAllFonts".</comment>
|
||||
</data>
|
||||
<data name="Profile_CreateUnfocusedAppearanceButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Verknüpfung</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Textformatierung</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>Tippen, um Symbole zu filtern</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Trennzeichen per Drag &amp; Drop</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Dieser Text wird zwischen den Pfaden mehrerer in das Terminal gezogener Dateien eingefügt.</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -2748,12 +2748,4 @@
|
||||
<value>Type to filter icons</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Drag and drop delimiter</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>This text will be inserted between the paths of multiple files dropped into the terminal.</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Ocultar la barra de título (requiere reiniciar)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Cuando está deshabilitada, la barra de título aparecerá encima de las pestañas.</value>
|
||||
@@ -983,11 +983,11 @@
|
||||
<comment>{Locked="‗"} An option to choose from for the "cursor shape" setting. When selected, the cursor will look like a stacked set of two underscores. The character in the parentheses is used to show what it looks like.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.Header" xml:space="preserve">
|
||||
<value>Tipo de fuente</value>
|
||||
<value>Estilo tipográfico</value>
|
||||
<comment>Header for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFaceBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Tipo de fuente</value>
|
||||
<value>Estilo tipográfico</value>
|
||||
<comment>Name for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.HelpText" xml:space="preserve">
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Directorio de inicio</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Directorio de inicio</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Directorio de inicio</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>El directorio en el que se inicia el perfil cuando se carga.</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Acceso directo</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Formato de texto</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>Escriba para filtrar iconos</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Delimitador de arrastrar y colocar</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Este texto se insertará entre las rutas de acceso de varios archivos colocados en el terminal.</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Masquer la barre de titre (redémarrage nécessaire)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Une fois désactivée, la barre de titre s’affiche au-dessus des onglets.</value>
|
||||
@@ -983,11 +983,11 @@
|
||||
<comment>{Locked="‗"} An option to choose from for the "cursor shape" setting. When selected, the cursor will look like a stacked set of two underscores. The character in the parentheses is used to show what it looks like.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.Header" xml:space="preserve">
|
||||
<value>Type de police</value>
|
||||
<value>Style de police</value>
|
||||
<comment>Header for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFaceBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Type de police</value>
|
||||
<value>Style de police</value>
|
||||
<comment>Name for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.HelpText" xml:space="preserve">
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Répertoire de démarrage</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Répertoire de démarrage</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Répertoire de démarrage</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>Répertoire dans lequel le shell démarre lorsqu’il est chargé.</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Raccourci</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Mise en forme du texte</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>Taper pour filtrer les icônes</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Glisser-déplacer le délimiteur</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Ce texte sera inséré entre les chemins d’accès de plusieurs fichiers déposés dans le terminal.</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Nascondi la barra del titolo (sarà necessario riavviare)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Se disabilitata, la barra del titolo verrà visualizzata sopra le schede.</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Directory iniziale</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Directory iniziale</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Directory iniziale</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>La directory che inizia il profilo durante il caricamento.</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Collegamento</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Formattazione testo</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>Digita per filtrare icone</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Trascina e rilascia il delimitatore</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Questo testo verrà inserito tra i percorsi di più file trascinati nel terminale.</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>タイトル バーを非表示にする (再起動が必要)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>無効にすると、タイトル バーがタブの上に表示されます。</value>
|
||||
@@ -983,11 +983,11 @@
|
||||
<comment>{Locked="‗"} An option to choose from for the "cursor shape" setting. When selected, the cursor will look like a stacked set of two underscores. The character in the parentheses is used to show what it looks like.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.Header" xml:space="preserve">
|
||||
<value>フォント フェイス</value>
|
||||
<value>フォント スタイル</value>
|
||||
<comment>Header for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFaceBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>フォント フェイス</value>
|
||||
<value>フォント スタイル</value>
|
||||
<comment>Name for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.HelpText" xml:space="preserve">
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>開始ディレクトリ</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>開始ディレクトリ</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>開始ディレクトリ</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>プロファイルが読み込まれたときに開始されるディレクトリです。</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>ショートカット</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>テキストの書式設定</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>入力してアイコンをフィルター処理します</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>ドラッグ アンド ドロップ区切り記号</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>このテキストは、ターミナルにドロップされた複数のファイルのパスの間に挿入されます。</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -293,7 +293,7 @@
|
||||
<comment>Header for a control to set the query URL when using the "search web" action.</comment>
|
||||
</data>
|
||||
<data name="Globals_SearchWebDefaultQueryUrl.HelpText" xml:space="preserve">
|
||||
<value>자리 표시자 "%s" 검색 쿼리로 대체됩니다.</value>
|
||||
<value>자리 표시자 "%s"가 검색 쿼리로 바뀝니다.</value>
|
||||
<comment>{Locked="%s"} Additional text presented near "Globals_SearchWebDefaultQueryUrl.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_TrimBlockSelection.Header" xml:space="preserve">
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>제목 표시줄 숨기기(다시 시작해야 함)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>사용하지 않도록 설정하면 제목 표시줄이 탭 위에 표시됩니다.</value>
|
||||
@@ -983,11 +983,11 @@
|
||||
<comment>{Locked="‗"} An option to choose from for the "cursor shape" setting. When selected, the cursor will look like a stacked set of two underscores. The character in the parentheses is used to show what it looks like.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.Header" xml:space="preserve">
|
||||
<value>글꼴</value>
|
||||
<value>글꼴 스타일</value>
|
||||
<comment>Header for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFaceBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>글꼴</value>
|
||||
<value>글꼴 스타일</value>
|
||||
<comment>Name for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.HelpText" xml:space="preserve">
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>시작 디렉터리</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>시작 디렉터리</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>시작 디렉터리</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>프로필이 로드될 때 시작됩니다.</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>바로 가기</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>텍스트 서식 지정</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>입력하여 아이콘 필터링</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>끌어서 놓기 구분 기호</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>이 텍스트는 터미널에 놓인 여러 파일의 경로 사이에 삽입됩니다.</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Oculta a barra do título (requer reinicialização)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Quando desabilitada, a barra de título aparecerá acima das guias.</value>
|
||||
@@ -983,15 +983,15 @@
|
||||
<comment>{Locked="‗"} An option to choose from for the "cursor shape" setting. When selected, the cursor will look like a stacked set of two underscores. The character in the parentheses is used to show what it looks like.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.Header" xml:space="preserve">
|
||||
<value>Tipo de fonte</value>
|
||||
<value>Variação</value>
|
||||
<comment>Header for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFaceBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Tipo de fonte</value>
|
||||
<value>Variação</value>
|
||||
<comment>Name for a control to select the font for text in the app.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFace.HelpText" xml:space="preserve">
|
||||
<value>Pode utilizar vários tipos de letra separando-os com uma vírgula ASCII.</value>
|
||||
<value>Você pode usar várias fontes, separando-as com uma vírgula ASCII.</value>
|
||||
</data>
|
||||
<data name="Profile_FontSize.Header" xml:space="preserve">
|
||||
<value>Tamanho da fonte</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Diretório inicial</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Diretório inicial</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Diretório inicial</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>A pasta em que o perfil começa quando é carregado.</value>
|
||||
@@ -1742,7 +1742,7 @@
|
||||
<comment>A supplementary setting to the "font face" setting. Toggling this control updates the font face control to show all of the fonts installed.</comment>
|
||||
</data>
|
||||
<data name="Profile_FontFaceShowAllFonts.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Se habilitado, mostrar todas as fontes instaladas na lista acima. Caso contrário, mostrar apenas a lista de fontes com espaçamento mono.</value>
|
||||
<value>Se ativado, mostra todas as fontes instaladas na lista acima. Caso contrário, mostra apenas as fontes monoespaçadas.</value>
|
||||
<comment>A description for what the supplementary "show all fonts" setting does. Presented near "Profile_FontFaceShowAllFonts".</comment>
|
||||
</data>
|
||||
<data name="Profile_CreateUnfocusedAppearanceButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Atalho</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Formatação de Texto</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>Digite para filtrar ícones</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Delimitador de Arrastar e soltar</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Este texto será inserido entre os caminhos de vários arquivos descartados no terminal.</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -293,7 +293,7 @@
|
||||
<comment>Header for a control to set the query URL when using the "search web" action.</comment>
|
||||
</data>
|
||||
<data name="Globals_SearchWebDefaultQueryUrl.HelpText" xml:space="preserve">
|
||||
<value>Ţђě рłд¢èнøĺđĕг "%s" щіłĺ ѓēφŀāćεđ ẃĩτђ τђе šέªґ¢ħ qύėгў. !!! !!! !!! !!! !!! !!</value>
|
||||
<value>Ţђě рłд¢èнøĺđĕг "%s" щіłĺ ьē ŕěρļąč℮ď ẁїτђ τђέ śеªřсħ qцегỳ. !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>{Locked="%s"} Additional text presented near "Globals_SearchWebDefaultQueryUrl.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_TrimBlockSelection.Header" xml:space="preserve">
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Ĥìđε тħê τīţĺё ъªř (ŗėqūΐŗêś яеľаϋʼnčћ) !!! !!! !!! !!</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Ẃћèп ðϊŝαъłėð, тнė ťĭτłê вąѓ ẁιĺł ąφφёǻŕ äвöνė ŧħė ťãьś. !!! !!! !!! !!! !!! !</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Ŝταяτìлĝ ðĩѓ℮ćτоŗỳ !!! !!</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Ѕťåřťіπġ đíгëĉţöґγ !!! !!</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Šтдřтíⁿģ đϊŕёςŧôŗў !!! !!</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>Ţћé đĭŗéçťòŕу τħе рѓøƒĩŀе śťªřťş ïή ẅћĕл îţ ίѕ ŀбдδėď. !!! !!! !!! !!! !!! !</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Şħōяŧ¢цτ !!</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Ťĕхτ ₣ôямåτţίʼnğ !!! !</value>
|
||||
@@ -2748,12 +2748,4 @@
|
||||
<value>Тÿρě ţθ ƒíŀŧēŗ īçōйš !!! !!!</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Đґâġ ąńð δŗορ ďèŀιмïţ℮я !!! !!! </value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Тĥїś ťэхť ẃĭŀł вё îⁿŝέŗŧеď вēťщ℮ěπ τĥę ρªτħѕ óƒ мџĺţīрℓé ƒĭļèś đяǿρрεδ ιйţθ ţħê ţèřмĭлªŀ. !!! !!! !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
@@ -293,7 +293,7 @@
|
||||
<comment>Header for a control to set the query URL when using the "search web" action.</comment>
|
||||
</data>
|
||||
<data name="Globals_SearchWebDefaultQueryUrl.HelpText" xml:space="preserve">
|
||||
<value>Ţђě рłд¢èнøĺđĕг "%s" щіłĺ ѓēφŀāćεđ ẃĩτђ τђе šέªґ¢ħ qύėгў. !!! !!! !!! !!! !!! !!</value>
|
||||
<value>Ţђě рłд¢èнøĺđĕг "%s" щіłĺ ьē ŕěρļąč℮ď ẁїτђ τђέ śеªřсħ qцегỳ. !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>{Locked="%s"} Additional text presented near "Globals_SearchWebDefaultQueryUrl.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_TrimBlockSelection.Header" xml:space="preserve">
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Ĥìđε тħê τīţĺё ъªř (ŗėqūΐŗêś яеľаϋʼnčћ) !!! !!! !!! !!</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Ẃћèп ðϊŝαъłėð, тнė ťĭτłê вąѓ ẁιĺł ąφφёǻŕ äвöνė ŧħė ťãьś. !!! !!! !!! !!! !!! !</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Ŝταяτìлĝ ðĩѓ℮ćτоŗỳ !!! !!</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Ѕťåřťіπġ đíгëĉţöґγ !!! !!</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Šтдřтíⁿģ đϊŕёςŧôŗў !!! !!</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>Ţћé đĭŗéçťòŕу τħе рѓøƒĩŀе śťªřťş ïή ẅћĕл îţ ίѕ ŀбдδėď. !!! !!! !!! !!! !!! !</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Şħōяŧ¢цτ !!</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Ťĕхτ ₣ôямåτţίʼnğ !!! !</value>
|
||||
@@ -2748,12 +2748,4 @@
|
||||
<value>Тÿρě ţθ ƒíŀŧēŗ īçōйš !!! !!!</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Đґâġ ąńð δŗορ ďèŀιмïţ℮я !!! !!! </value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Тĥїś ťэхť ẃĭŀł вё îⁿŝέŗŧеď вēťщ℮ěπ τĥę ρªτħѕ óƒ мџĺţīрℓé ƒĭļèś đяǿρрεδ ιйţθ ţħê ţèřмĭлªŀ. !!! !!! !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
@@ -293,7 +293,7 @@
|
||||
<comment>Header for a control to set the query URL when using the "search web" action.</comment>
|
||||
</data>
|
||||
<data name="Globals_SearchWebDefaultQueryUrl.HelpText" xml:space="preserve">
|
||||
<value>Ţђě рłд¢èнøĺđĕг "%s" щіłĺ ѓēφŀāćεđ ẃĩτђ τђе šέªґ¢ħ qύėгў. !!! !!! !!! !!! !!! !!</value>
|
||||
<value>Ţђě рłд¢èнøĺđĕг "%s" щіłĺ ьē ŕěρļąč℮ď ẁїτђ τђέ śеªřсħ qцегỳ. !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>{Locked="%s"} Additional text presented near "Globals_SearchWebDefaultQueryUrl.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_TrimBlockSelection.Header" xml:space="preserve">
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Ĥìđε тħê τīţĺё ъªř (ŗėqūΐŗêś яеľаϋʼnčћ) !!! !!! !!! !!</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Ẃћèп ðϊŝαъłėð, тнė ťĭτłê вąѓ ẁιĺł ąφφёǻŕ äвöνė ŧħė ťãьś. !!! !!! !!! !!! !!! !</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Ŝταяτìлĝ ðĩѓ℮ćτоŗỳ !!! !!</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Ѕťåřťіπġ đíгëĉţöґγ !!! !!</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Šтдřтíⁿģ đϊŕёςŧôŗў !!! !!</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>Ţћé đĭŗéçťòŕу τħе рѓøƒĩŀе śťªřťş ïή ẅћĕл îţ ίѕ ŀбдδėď. !!! !!! !!! !!! !!! !</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Şħōяŧ¢цτ !!</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Ťĕхτ ₣ôямåτţίʼnğ !!! !</value>
|
||||
@@ -2748,12 +2748,4 @@
|
||||
<value>Тÿρě ţθ ƒíŀŧēŗ īçōйš !!! !!!</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Đґâġ ąńð δŗορ ďèŀιмïţ℮я !!! !!! </value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Тĥїś ťэхť ẃĭŀł вё îⁿŝέŗŧеď вēťщ℮ěπ τĥę ρªτħѕ óƒ мџĺţīрℓé ƒĭļèś đяǿρрεδ ιйţθ ţħê ţèřмĭлªŀ. !!! !!! !!! !!! !!! !!! !!! !!! !!!</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
</root>
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>Скрыть заголовок окна (требуется перезапуск)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>Если этот параметр отключен, строка заголовка будет отображаться над вкладками.</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Начальный каталог</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>Запуск каталога</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Начальный каталог</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>Каталог, запускаемый профилем при загрузке.</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Сочетание клавиш</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>Форматирование текста</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>Введите текст для фильтрации значков</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>Перетащите разделитель</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>Этот текст будет вставлен между путями нескольких файлов, перетащенных в терминал.</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>隐藏标题栏(需要重新启动)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>禁用后,标题栏将显示在选项卡上方。</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>启动目录</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>启动目录</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>正在启动目录</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>加载配置文件时启动的目录。</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>快捷方式</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>文本格式</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>键入以筛选图标</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>拖放分隔符</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>此文本将在放置到终端的多个文件的路径之间插入。</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -293,7 +293,7 @@
|
||||
<comment>Header for a control to set the query URL when using the "search web" action.</comment>
|
||||
</data>
|
||||
<data name="Globals_SearchWebDefaultQueryUrl.HelpText" xml:space="preserve">
|
||||
<value>佔位元 "%s" 將取代為搜尋查詢。</value>
|
||||
<value>預留位置 "%s" 將以搜尋查詢取代。</value>
|
||||
<comment>{Locked="%s"} Additional text presented near "Globals_SearchWebDefaultQueryUrl.Header".</comment>
|
||||
</data>
|
||||
<data name="Globals_TrimBlockSelection.Header" xml:space="preserve">
|
||||
@@ -507,7 +507,7 @@
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.Header" xml:space="preserve">
|
||||
<value>隱藏標題列 (需要重新啟動)</value>
|
||||
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
|
||||
<comment>Header for a control to toggle whether or not the title bar should be shown. Changing this setting requires the user to relaunch the app.</comment>
|
||||
</data>
|
||||
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
|
||||
<value>停用時,標題列會出現在索引標籤上方。</value>
|
||||
@@ -1195,15 +1195,15 @@
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>起始目錄</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.Header" xml:space="preserve">
|
||||
<value>啟動時載入的目錄</value>
|
||||
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Header for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>起始目錄</value>
|
||||
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
|
||||
<comment>Name for a control to determine the session's initial directory. This is on a text box that accepts folder paths.</comment>
|
||||
</data>
|
||||
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
|
||||
<value>載入時,設定檔起始的目錄。</value>
|
||||
@@ -2147,7 +2147,7 @@
|
||||
</data>
|
||||
<data name="KeyChordListener.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>捷徑</value>
|
||||
<comment>The label for a "key chord listener" control that sets the keys a key binding is bound to.</comment>
|
||||
<comment>The label for a "key chord listener" control that sets the keys to which a key binding is bound.</comment>
|
||||
</data>
|
||||
<data name="Appearance_TextFormattingHeader.Text" xml:space="preserve">
|
||||
<value>文字格式設定</value>
|
||||
@@ -2744,12 +2744,4 @@
|
||||
<value>輸入以篩選圖示</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.Header" xml:space="preserve">
|
||||
<value>拖放分隔符號</value>
|
||||
<comment>Header for a control to set the delimiter used when dragging multiple files into the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_DragDropDelimiter.HelpText" xml:space="preserve">
|
||||
<value>這些文字會插入多個丟入終端機的檔案路徑之間。</value>
|
||||
<comment>A description for what the "drag drop delimiter" setting does.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -31,18 +31,19 @@ AppearanceConfig::AppearanceConfig(winrt::weak_ref<Model::Profile> sourceProfile
|
||||
winrt::com_ptr<AppearanceConfig> AppearanceConfig::CopyAppearance(const AppearanceConfig* source, winrt::weak_ref<Model::Profile> sourceProfile)
|
||||
{
|
||||
auto appearance{ winrt::make_self<AppearanceConfig>(std::move(sourceProfile)) };
|
||||
appearance->_Foreground = source->_Foreground;
|
||||
appearance->_Background = source->_Background;
|
||||
appearance->_SelectionBackground = source->_SelectionBackground;
|
||||
appearance->_CursorColor = source->_CursorColor;
|
||||
appearance->_Opacity = source->_Opacity;
|
||||
|
||||
appearance->_json = source->_json;
|
||||
appearance->_DarkColorSchemeName = source->_DarkColorSchemeName;
|
||||
appearance->_LightColorSchemeName = source->_LightColorSchemeName;
|
||||
|
||||
// JSON-backed settings (Foreground, Background, SelectionBackground, CursorColor,
|
||||
// Opacity, DarkColorSchemeName, LightColorSchemeName, MTSM settings) all live in
|
||||
// _json, which is already deep-copied above.
|
||||
|
||||
// Complex/mutable settings — backing fields for resolution lifecycle.
|
||||
// _json (copied above) is the source of truth; backing fields hold resolved runtime state.
|
||||
appearance->_PixelShaderPath = source->_PixelShaderPath;
|
||||
appearance->_PixelShaderImagePath = source->_PixelShaderImagePath;
|
||||
appearance->_BackgroundImagePath = source->_BackgroundImagePath;
|
||||
#define APPEARANCE_SETTINGS_COPY(type, name, jsonKey, ...) \
|
||||
appearance->_##name = source->_##name;
|
||||
MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_COPY)
|
||||
#undef APPEARANCE_SETTINGS_COPY
|
||||
|
||||
return appearance;
|
||||
}
|
||||
@@ -51,126 +52,33 @@ Json::Value AppearanceConfig::ToJson() const
|
||||
{
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
|
||||
// Nullable color settings: key presence matters (explicit null is valid)
|
||||
for (const auto& key : { ForegroundKey, BackgroundKey, SelectionBackgroundKey, CursorColorKey })
|
||||
JsonUtils::SetValueForKey(json, ForegroundKey, _Foreground);
|
||||
JsonUtils::SetValueForKey(json, BackgroundKey, _Background);
|
||||
JsonUtils::SetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
|
||||
JsonUtils::SetValueForKey(json, CursorColorKey, _CursorColor);
|
||||
JsonUtils::SetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<float, IntAsFloatPercentConversionTrait>{});
|
||||
if (HasDarkColorSchemeName() || HasLightColorSchemeName())
|
||||
{
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, key);
|
||||
// check if the setting is coming from the UI, if so grab the ColorSchemeName until the settings UI is fixed.
|
||||
if (_LightColorSchemeName != _DarkColorSchemeName)
|
||||
{
|
||||
JsonUtils::SetValueForKey(json["colorScheme"], "dark", _DarkColorSchemeName);
|
||||
JsonUtils::SetValueForKey(json["colorScheme"], "light", _LightColorSchemeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonUtils::SetValueForKey(json, "colorScheme", _DarkColorSchemeName);
|
||||
}
|
||||
}
|
||||
|
||||
// Opacity: copy from _json (may be int or float — preserves original form)
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, OpacityKey);
|
||||
|
||||
// ColorScheme: ConversionTrait<ColorSchemeReference> handles string<->object form.
|
||||
// _json already has the correct serialized form from SetValueForKey.
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, ColorSchemeKey);
|
||||
|
||||
// MTSM appearance settings: copy from _json (the source of truth)
|
||||
#define APPEARANCE_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, jsonKey);
|
||||
JsonUtils::SetValueForKey(json, jsonKey, _##name);
|
||||
MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_TO_JSON)
|
||||
#undef APPEARANCE_SETTINGS_TO_JSON
|
||||
|
||||
// Complex/mutable settings — read from _json (source of truth), not backing fields
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, "experimental.pixelShaderPath");
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, "experimental.pixelShaderImagePath");
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, "backgroundImage");
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
bool AppearanceConfig::HasSetting(AppearanceSettingKey key) const
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
#define _APPEARANCE_HAS_SETTING(type, name, jsonKey, ...) \
|
||||
case AppearanceSettingKey::name: \
|
||||
return Has##name();
|
||||
MTSM_APPEARANCE_SETTINGS(_APPEARANCE_HAS_SETTING)
|
||||
#undef _APPEARANCE_HAS_SETTING
|
||||
case AppearanceSettingKey::_Foreground:
|
||||
return HasForeground();
|
||||
case AppearanceSettingKey::_Background:
|
||||
return HasBackground();
|
||||
case AppearanceSettingKey::_SelectionBackground:
|
||||
return HasSelectionBackground();
|
||||
case AppearanceSettingKey::_CursorColor:
|
||||
return HasCursorColor();
|
||||
case AppearanceSettingKey::_Opacity:
|
||||
return HasOpacity();
|
||||
case AppearanceSettingKey::_DarkColorSchemeName:
|
||||
return HasDarkColorSchemeName();
|
||||
case AppearanceSettingKey::_LightColorSchemeName:
|
||||
return HasLightColorSchemeName();
|
||||
case AppearanceSettingKey::_PixelShaderPath:
|
||||
return HasPixelShaderPath();
|
||||
case AppearanceSettingKey::_PixelShaderImagePath:
|
||||
return HasPixelShaderImagePath();
|
||||
case AppearanceSettingKey::_BackgroundImagePath:
|
||||
return HasBackgroundImagePath();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AppearanceConfig::ClearSetting(AppearanceSettingKey key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
#define _APPEARANCE_CLEAR_SETTING(type, name, jsonKey, ...) \
|
||||
case AppearanceSettingKey::name: \
|
||||
Clear##name(); \
|
||||
break;
|
||||
MTSM_APPEARANCE_SETTINGS(_APPEARANCE_CLEAR_SETTING)
|
||||
#undef _APPEARANCE_CLEAR_SETTING
|
||||
case AppearanceSettingKey::_Foreground:
|
||||
ClearForeground();
|
||||
break;
|
||||
case AppearanceSettingKey::_Background:
|
||||
ClearBackground();
|
||||
break;
|
||||
case AppearanceSettingKey::_SelectionBackground:
|
||||
ClearSelectionBackground();
|
||||
break;
|
||||
case AppearanceSettingKey::_CursorColor:
|
||||
ClearCursorColor();
|
||||
break;
|
||||
case AppearanceSettingKey::_Opacity:
|
||||
ClearOpacity();
|
||||
break;
|
||||
case AppearanceSettingKey::_DarkColorSchemeName:
|
||||
ClearDarkColorSchemeName();
|
||||
break;
|
||||
case AppearanceSettingKey::_LightColorSchemeName:
|
||||
ClearLightColorSchemeName();
|
||||
break;
|
||||
case AppearanceSettingKey::_PixelShaderPath:
|
||||
ClearPixelShaderPath();
|
||||
break;
|
||||
case AppearanceSettingKey::_PixelShaderImagePath:
|
||||
ClearPixelShaderImagePath();
|
||||
break;
|
||||
case AppearanceSettingKey::_BackgroundImagePath:
|
||||
ClearBackgroundImagePath();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<AppearanceSettingKey> AppearanceConfig::CurrentSettings() const
|
||||
{
|
||||
std::vector<AppearanceSettingKey> result;
|
||||
for (auto i = 0; i < static_cast<int>(AppearanceSettingKey::SETTINGS_SIZE); i++)
|
||||
{
|
||||
const auto key = static_cast<AppearanceSettingKey>(i);
|
||||
if (HasSetting(key))
|
||||
{
|
||||
result.push_back(key);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Layer values from the given json object on top of the existing properties
|
||||
// of this object. For any keys we're expecting to be able to parse in the
|
||||
@@ -184,50 +92,45 @@ std::vector<AppearanceSettingKey> AppearanceConfig::CurrentSettings() const
|
||||
// - json: an object which should be a partial serialization of an AppearanceConfig object.
|
||||
void AppearanceConfig::LayerJson(const Json::Value& json)
|
||||
{
|
||||
// Merge incoming JSON keys into stored _json (key-wise, not replacement).
|
||||
// AppearanceConfig receives the full profile JSON; we store all keys and
|
||||
// read only appearance-relevant ones from it.
|
||||
JsonUtils::MergeJsonKeys(json, _json);
|
||||
JsonUtils::GetValueForKey(json, ForegroundKey, _Foreground);
|
||||
_logSettingIfSet(ForegroundKey, _Foreground.has_value());
|
||||
|
||||
// Nullable color settings are now JSON-backed. Log which were set.
|
||||
_logSettingIfSet(ForegroundKey, HasForeground());
|
||||
_logSettingIfSet(BackgroundKey, HasBackground());
|
||||
_logSettingIfSet(SelectionBackgroundKey, HasSelectionBackground());
|
||||
_logSettingIfSet(CursorColorKey, HasCursorColor());
|
||||
JsonUtils::GetValueForKey(json, BackgroundKey, _Background);
|
||||
_logSettingIfSet(BackgroundKey, _Background.has_value());
|
||||
|
||||
// Normalize legacy opacity key into canonical _json key
|
||||
if (json.isMember(JsonKey(LegacyAcrylicTransparencyKey)))
|
||||
JsonUtils::GetValueForKey(json, SelectionBackgroundKey, _SelectionBackground);
|
||||
_logSettingIfSet(SelectionBackgroundKey, _SelectionBackground.has_value());
|
||||
|
||||
JsonUtils::GetValueForKey(json, CursorColorKey, _CursorColor);
|
||||
_logSettingIfSet(CursorColorKey, _CursorColor.has_value());
|
||||
|
||||
JsonUtils::GetValueForKey(json, LegacyAcrylicTransparencyKey, _Opacity);
|
||||
JsonUtils::GetValueForKey(json, OpacityKey, _Opacity, JsonUtils::OptionalConverter<float, IntAsFloatPercentConversionTrait>{});
|
||||
_logSettingIfSet(OpacityKey, _Opacity.has_value());
|
||||
|
||||
if (json["colorScheme"].isString())
|
||||
{
|
||||
_json[JsonKey(OpacityKey)] = json[JsonKey(LegacyAcrylicTransparencyKey)];
|
||||
// to make the UI happy, set ColorSchemeName.
|
||||
JsonUtils::GetValueForKey(json, ColorSchemeKey, _DarkColorSchemeName);
|
||||
_LightColorSchemeName = _DarkColorSchemeName;
|
||||
_logSettingSet(ColorSchemeKey);
|
||||
}
|
||||
// Normalize integer percent to float (e.g. 50 → 0.5)
|
||||
if (_json.isMember(JsonKey(OpacityKey)) && _json[JsonKey(OpacityKey)].isInt())
|
||||
else if (json["colorScheme"].isObject())
|
||||
{
|
||||
_json[JsonKey(OpacityKey)] = _json[JsonKey(OpacityKey)].asInt() / 100.0f;
|
||||
// to make the UI happy, set ColorSchemeName to whatever the dark value is.
|
||||
JsonUtils::GetValueForKey(json["colorScheme"], "dark", _DarkColorSchemeName);
|
||||
JsonUtils::GetValueForKey(json["colorScheme"], "light", _LightColorSchemeName);
|
||||
|
||||
_logSettingSet("colorScheme.dark");
|
||||
_logSettingSet("colorScheme.light");
|
||||
}
|
||||
_logSettingIfSet(OpacityKey, HasOpacity());
|
||||
|
||||
// ColorScheme: ConversionTrait<ColorSchemeReference> handles string↔object normalization.
|
||||
// The raw JSON is stored in _json; the trait interprets it on read.
|
||||
_logSettingIfSet(ColorSchemeKey, HasColorSchemeRef());
|
||||
|
||||
// MTSM settings are now JSON-backed (no backing fields).
|
||||
// Values are already in _json from the merge step above.
|
||||
// We only need to log which settings were set in this layer.
|
||||
#define APPEARANCE_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
|
||||
_logSettingIfSet(jsonKey, json.isMember(jsonKey) && !json[jsonKey].isNull());
|
||||
JsonUtils::GetValueForKey(json, jsonKey, _##name); \
|
||||
_logSettingIfSet(jsonKey, _##name.has_value());
|
||||
|
||||
MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_LAYER_JSON)
|
||||
#undef APPEARANCE_SETTINGS_LAYER_JSON
|
||||
|
||||
// Complex/mutable settings — backing fields populated from _json for resolution lifecycle.
|
||||
// _json is the source of truth for serialization; backing fields are for resolution lifecycle.
|
||||
JsonUtils::GetValueForKey(json, "experimental.pixelShaderPath", _PixelShaderPath);
|
||||
_logSettingIfSet("experimental.pixelShaderPath", _PixelShaderPath.has_value());
|
||||
JsonUtils::GetValueForKey(json, "experimental.pixelShaderImagePath", _PixelShaderImagePath);
|
||||
_logSettingIfSet("experimental.pixelShaderImagePath", _PixelShaderImagePath.has_value());
|
||||
JsonUtils::GetValueForKey(json, "backgroundImage", _BackgroundImagePath);
|
||||
_logSettingIfSet("backgroundImage", _BackgroundImagePath.has_value());
|
||||
}
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Model::Profile AppearanceConfig::SourceProfile()
|
||||
|
||||
@@ -18,80 +18,11 @@ Author(s):
|
||||
|
||||
#include "AppearanceConfig.g.h"
|
||||
#include "JsonUtils.h"
|
||||
#include "TerminalSettingsSerializationHelpers.h"
|
||||
#include "IInheritable.h"
|
||||
#include "MTSMSettings.h"
|
||||
#include "MediaResourceSupport.h"
|
||||
#include <DefaultSettings.h>
|
||||
|
||||
// ColorSchemeReference: a pair of color scheme names for dark and light themes.
|
||||
// Represents the polymorphic "colorScheme" JSON key, which can be either:
|
||||
// "colorScheme": "Campbell" → { dark: "Campbell", light: "Campbell" }
|
||||
// "colorScheme": { "dark": "X", "light": "Y" } → { dark: "X", light: "Y" }
|
||||
struct ColorSchemeReference
|
||||
{
|
||||
winrt::hstring dark{ L"Campbell" };
|
||||
winrt::hstring light{ L"Campbell" };
|
||||
|
||||
static ColorSchemeReference Default() { return {}; }
|
||||
bool operator==(const ColorSchemeReference&) const = default;
|
||||
};
|
||||
|
||||
namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
||||
{
|
||||
template<>
|
||||
struct ConversionTrait<ColorSchemeReference>
|
||||
{
|
||||
ColorSchemeReference FromJson(const Json::Value& json)
|
||||
{
|
||||
ColorSchemeReference result;
|
||||
if (json.isString())
|
||||
{
|
||||
// Simple form: both dark and light use the same scheme
|
||||
const auto name = winrt::hstring{ til::u8u16(json.asString()) };
|
||||
result.dark = name;
|
||||
result.light = name;
|
||||
}
|
||||
else if (json.isObject())
|
||||
{
|
||||
// Structured form: { "dark": "...", "light": "..." }
|
||||
if (json.isMember("dark"))
|
||||
{
|
||||
result.dark = winrt::hstring{ til::u8u16(json["dark"].asString()) };
|
||||
}
|
||||
if (json.isMember("light"))
|
||||
{
|
||||
result.light = winrt::hstring{ til::u8u16(json["light"].asString()) };
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CanConvert(const Json::Value& json) const
|
||||
{
|
||||
return json.isString() || json.isObject();
|
||||
}
|
||||
|
||||
Json::Value ToJson(const ColorSchemeReference& val)
|
||||
{
|
||||
// Collapse to string when dark == light
|
||||
if (val.dark == val.light)
|
||||
{
|
||||
return til::u16u8(val.dark);
|
||||
}
|
||||
Json::Value obj{ Json::ValueType::objectValue };
|
||||
obj["dark"] = til::u16u8(val.dark);
|
||||
obj["light"] = til::u16u8(val.light);
|
||||
return obj;
|
||||
}
|
||||
|
||||
std::string TypeDescription() const
|
||||
{
|
||||
return "color scheme name (string or {dark, light})";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
struct AppearanceConfig : AppearanceConfigT<AppearanceConfig, IMediaResourceContainer>, IInheritable<AppearanceConfig>
|
||||
@@ -107,65 +38,22 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
void ResolveMediaResources(const Model::MediaResourceResolver& resolver);
|
||||
|
||||
// Generic setting access via SettingKey
|
||||
bool HasSetting(AppearanceSettingKey key) const;
|
||||
void ClearSetting(AppearanceSettingKey key);
|
||||
std::vector<AppearanceSettingKey> CurrentSettings() const;
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, Foreground, nullptr);
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, Background, nullptr);
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, SelectionBackground, nullptr);
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, CursorColor, nullptr);
|
||||
INHERITABLE_SETTING(Model::IAppearanceConfig, float, Opacity, 1.0f);
|
||||
|
||||
// Nullable color settings (JSON-backed)
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, Foreground, "foreground", nullptr)
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, Background, "background", nullptr)
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, SelectionBackground, "selectionBackground", nullptr)
|
||||
INHERITABLE_NULLABLE_SETTING(Model::IAppearanceConfig, Microsoft::Terminal::Core::Color, CursorColor, "cursorColor", nullptr)
|
||||
|
||||
// Opacity: JSON-backed with normalization (int percent → float in LayerJson)
|
||||
INHERITABLE_SETTING(Model::IAppearanceConfig, float, Opacity, "opacity", 1.0f)
|
||||
|
||||
// ColorScheme: JSON-backed via INHERITABLE_SETTING with ColorSchemeReference struct.
|
||||
// The polymorphic JSON key ("colorScheme" as string or object) is handled by
|
||||
// ConversionTrait<ColorSchemeReference>. The macro provides Has/Clear/OverrideSource.
|
||||
// Thin wrappers expose the IDL-required DarkColorSchemeName / LightColorSchemeName.
|
||||
INHERITABLE_SETTING(Model::IAppearanceConfig, ColorSchemeReference, ColorSchemeRef, "colorScheme", ColorSchemeReference::Default())
|
||||
public:
|
||||
hstring DarkColorSchemeName() const { return ColorSchemeRef().dark; }
|
||||
void DarkColorSchemeName(const hstring& value)
|
||||
{
|
||||
auto ref = ColorSchemeRef();
|
||||
ref.dark = value;
|
||||
ColorSchemeRef(ref);
|
||||
}
|
||||
bool HasDarkColorSchemeName() const { return HasColorSchemeRef(); }
|
||||
void ClearDarkColorSchemeName() { ClearColorSchemeRef(); }
|
||||
Model::IAppearanceConfig DarkColorSchemeNameOverrideSource() { return ColorSchemeRefOverrideSource(); }
|
||||
|
||||
hstring LightColorSchemeName() const { return ColorSchemeRef().light; }
|
||||
void LightColorSchemeName(const hstring& value)
|
||||
{
|
||||
auto ref = ColorSchemeRef();
|
||||
ref.light = value;
|
||||
ColorSchemeRef(ref);
|
||||
}
|
||||
bool HasLightColorSchemeName() const { return HasColorSchemeRef(); }
|
||||
void ClearLightColorSchemeName() { ClearColorSchemeRef(); }
|
||||
Model::IAppearanceConfig LightColorSchemeNameOverrideSource() { return ColorSchemeRefOverrideSource(); }
|
||||
INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, DarkColorSchemeName, L"Campbell");
|
||||
INHERITABLE_SETTING(Model::IAppearanceConfig, hstring, LightColorSchemeName, L"Campbell");
|
||||
|
||||
#define APPEARANCE_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
|
||||
INHERITABLE_SETTING(Model::IAppearanceConfig, type, name, jsonKey, ##__VA_ARGS__)
|
||||
INHERITABLE_SETTING(Model::IAppearanceConfig, type, name, ##__VA_ARGS__)
|
||||
MTSM_APPEARANCE_SETTINGS(APPEARANCE_SETTINGS_INITIALIZE)
|
||||
#undef APPEARANCE_SETTINGS_INITIALIZE
|
||||
|
||||
// IMediaResource settings with backing fields for resolution lifecycle.
|
||||
// See IInheritable.h for the INHERITABLE_MEDIA_RESOURCE_SETTING macro definition.
|
||||
INHERITABLE_MEDIA_RESOURCE_SETTING(Model::IAppearanceConfig, PixelShaderPath, "experimental.pixelShaderPath", implementation::MediaResource::Empty())
|
||||
INHERITABLE_MEDIA_RESOURCE_SETTING(Model::IAppearanceConfig, PixelShaderImagePath, "experimental.pixelShaderImagePath", implementation::MediaResource::Empty())
|
||||
INHERITABLE_MEDIA_RESOURCE_SETTING(Model::IAppearanceConfig, BackgroundImagePath, "backgroundImage", implementation::MediaResource::Empty())
|
||||
|
||||
private:
|
||||
winrt::weak_ref<Profile> _sourceProfile;
|
||||
|
||||
// Raw JSON for this layer (appearance-relevant keys only).
|
||||
Json::Value _json{ Json::ValueType::objectValue };
|
||||
|
||||
std::set<std::string> _changeLog;
|
||||
|
||||
void _logSettingSet(const std::string_view& setting);
|
||||
|
||||
@@ -12,8 +12,6 @@ using namespace Microsoft::Terminal::Settings::Model;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
|
||||
|
||||
static constexpr std::string_view FontInfoKey{ "font" };
|
||||
static constexpr std::string_view FontAxesKey{ "axes" };
|
||||
static constexpr std::string_view FontFeaturesKey{ "features" };
|
||||
static constexpr std::string_view LegacyFontFaceKey{ "fontFace" };
|
||||
static constexpr std::string_view LegacyFontSizeKey{ "fontSize" };
|
||||
static constexpr std::string_view LegacyFontWeightKey{ "fontWeight" };
|
||||
@@ -27,11 +25,29 @@ winrt::com_ptr<FontConfig> FontConfig::CopyFontInfo(const FontConfig* source, wi
|
||||
{
|
||||
auto fontInfo{ winrt::make_self<FontConfig>(std::move(sourceProfile)) };
|
||||
|
||||
fontInfo->_json = source->_json;
|
||||
#define FONT_SETTINGS_COPY(type, name, jsonKey, ...) \
|
||||
fontInfo->_##name = source->_##name;
|
||||
MTSM_FONT_SETTINGS(FONT_SETTINGS_COPY)
|
||||
#undef FONT_SETTINGS_COPY
|
||||
|
||||
// FontAxes and FontFeatures are now JSON-backed — handled by _json copy above.
|
||||
// No manual deep-copy needed; the JSON-backed getter returns a fresh deserialized
|
||||
// collection each time.
|
||||
// We cannot simply copy the font axes and features with `fontInfo->_FontAxes = source->_FontAxes;`
|
||||
// since that'll just create a reference; we have to manually copy the values.
|
||||
static constexpr auto cloneFontMap = [](const IFontFeatureMap& map) {
|
||||
std::map<winrt::hstring, float> fontAxes;
|
||||
for (const auto& [k, v] : map)
|
||||
{
|
||||
fontAxes.emplace(k, v);
|
||||
}
|
||||
return winrt::single_threaded_map(std::move(fontAxes));
|
||||
};
|
||||
if (source->_FontAxes)
|
||||
{
|
||||
fontInfo->_FontAxes = cloneFontMap(*source->_FontAxes);
|
||||
}
|
||||
if (source->_FontFeatures)
|
||||
{
|
||||
fontInfo->_FontFeatures = cloneFontMap(*source->_FontFeatures);
|
||||
}
|
||||
|
||||
return fontInfo;
|
||||
}
|
||||
@@ -40,58 +56,14 @@ Json::Value FontConfig::ToJson() const
|
||||
{
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
|
||||
// MTSM font settings: copy from _json (the source of truth)
|
||||
#define FONT_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, jsonKey);
|
||||
JsonUtils::SetValueForKey(json, jsonKey, _##name);
|
||||
MTSM_FONT_SETTINGS(FONT_SETTINGS_TO_JSON)
|
||||
#undef FONT_SETTINGS_TO_JSON
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
bool FontConfig::HasSetting(FontSettingKey key) const
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
#define _FONT_HAS_SETTING(type, name, jsonKey, ...) \
|
||||
case FontSettingKey::name: \
|
||||
return Has##name();
|
||||
MTSM_FONT_SETTINGS(_FONT_HAS_SETTING)
|
||||
#undef _FONT_HAS_SETTING
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FontConfig::ClearSetting(FontSettingKey key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
#define _FONT_CLEAR_SETTING(type, name, jsonKey, ...) \
|
||||
case FontSettingKey::name: \
|
||||
Clear##name(); \
|
||||
break;
|
||||
MTSM_FONT_SETTINGS(_FONT_CLEAR_SETTING)
|
||||
#undef _FONT_CLEAR_SETTING
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<FontSettingKey> FontConfig::CurrentSettings() const
|
||||
{
|
||||
std::vector<FontSettingKey> result;
|
||||
for (auto i = 0; i < static_cast<int>(FontSettingKey::SETTINGS_SIZE); i++)
|
||||
{
|
||||
const auto key = static_cast<FontSettingKey>(i);
|
||||
if (HasSetting(key))
|
||||
{
|
||||
result.push_back(key);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Layer values from the given json object on top of the existing properties
|
||||
// of this object. For any keys we're expecting to be able to parse in the
|
||||
@@ -111,38 +83,25 @@ void FontConfig::LayerJson(const Json::Value& json)
|
||||
{
|
||||
// A font object is defined, use that
|
||||
const auto fontInfoJson = json[JsonKey(FontInfoKey)];
|
||||
|
||||
// Merge the font sub-object into stored _json (font-object shape).
|
||||
JsonUtils::MergeJsonKeys(fontInfoJson, _json);
|
||||
|
||||
// MTSM font settings are now JSON-backed (including FontAxes/FontFeatures).
|
||||
// Values are already in _json. We only need to log which settings were set.
|
||||
#define FONT_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
|
||||
_logSettingIfSet(jsonKey, fontInfoJson.isMember(jsonKey) && !fontInfoJson[jsonKey].isNull());
|
||||
#define FONT_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
|
||||
JsonUtils::GetValueForKey(fontInfoJson, jsonKey, _##name); \
|
||||
_logSettingIfSet(jsonKey, _##name.has_value());
|
||||
|
||||
MTSM_FONT_SETTINGS(FONT_SETTINGS_LAYER_JSON)
|
||||
#undef FONT_SETTINGS_LAYER_JSON
|
||||
}
|
||||
else
|
||||
{
|
||||
// No font object is defined — normalize legacy flat keys into font-object shape.
|
||||
if (json.isMember(JsonKey(LegacyFontFaceKey)))
|
||||
{
|
||||
_json["face"] = json[JsonKey(LegacyFontFaceKey)];
|
||||
}
|
||||
if (json.isMember(JsonKey(LegacyFontSizeKey)))
|
||||
{
|
||||
_json["size"] = json[JsonKey(LegacyFontSizeKey)];
|
||||
}
|
||||
if (json.isMember(JsonKey(LegacyFontWeightKey)))
|
||||
{
|
||||
_json["weight"] = json[JsonKey(LegacyFontWeightKey)];
|
||||
}
|
||||
|
||||
// No font object is defined
|
||||
// Log settings as if they were a part of the font object
|
||||
_logSettingIfSet("face", json.isMember(JsonKey(LegacyFontFaceKey)));
|
||||
_logSettingIfSet("size", json.isMember(JsonKey(LegacyFontSizeKey)));
|
||||
_logSettingIfSet("weight", json.isMember(JsonKey(LegacyFontWeightKey)));
|
||||
JsonUtils::GetValueForKey(json, LegacyFontFaceKey, _FontFace);
|
||||
_logSettingIfSet("face", _FontFace.has_value());
|
||||
|
||||
JsonUtils::GetValueForKey(json, LegacyFontSizeKey, _FontSize);
|
||||
_logSettingIfSet("size", _FontSize.has_value());
|
||||
|
||||
JsonUtils::GetValueForKey(json, LegacyFontWeightKey, _FontWeight);
|
||||
_logSettingIfSet("weight", _FontWeight.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,16 +112,16 @@ winrt::Microsoft::Terminal::Settings::Model::Profile FontConfig::SourceProfile()
|
||||
|
||||
void FontConfig::_logSettingSet(const std::string_view& setting)
|
||||
{
|
||||
if (setting == FontAxesKey && HasFontAxes())
|
||||
if (setting == "axes" && _FontAxes.has_value())
|
||||
{
|
||||
for (const auto& [mapKey, _] : FontAxes())
|
||||
for (const auto& [mapKey, _] : _FontAxes.value())
|
||||
{
|
||||
_changeLog.emplace(fmt::format(FMT_COMPILE("{}.{}"), setting, til::u16u8(mapKey)));
|
||||
}
|
||||
}
|
||||
else if (setting == FontFeaturesKey && HasFontFeatures())
|
||||
else if (setting == "features" && _FontFeatures.has_value())
|
||||
{
|
||||
for (const auto& [mapKey, _] : FontFeatures())
|
||||
for (const auto& [mapKey, _] : _FontFeatures.value())
|
||||
{
|
||||
_changeLog.emplace(fmt::format(FMT_COMPILE("{}.{}"), setting, til::u16u8(mapKey)));
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ Author(s):
|
||||
#include "pch.h"
|
||||
#include "FontConfig.g.h"
|
||||
#include "JsonUtils.h"
|
||||
#include "TerminalSettingsSerializationHelpers.h"
|
||||
#include "MTSMSettings.h"
|
||||
#include "IInheritable.h"
|
||||
#include <DefaultSettings.h>
|
||||
@@ -40,22 +39,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
Model::Profile SourceProfile();
|
||||
|
||||
// Generic setting access via SettingKey
|
||||
bool HasSetting(FontSettingKey key) const;
|
||||
void ClearSetting(FontSettingKey key);
|
||||
std::vector<FontSettingKey> CurrentSettings() const;
|
||||
|
||||
#define FONT_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
|
||||
INHERITABLE_SETTING(Model::FontConfig, type, name, jsonKey, ##__VA_ARGS__)
|
||||
INHERITABLE_SETTING(Model::FontConfig, type, name, ##__VA_ARGS__)
|
||||
MTSM_FONT_SETTINGS(FONT_SETTINGS_INITIALIZE)
|
||||
#undef FONT_SETTINGS_INITIALIZE
|
||||
|
||||
private:
|
||||
winrt::weak_ref<Profile> _sourceProfile;
|
||||
|
||||
// Raw JSON for this layer (font sub-object shape).
|
||||
Json::Value _json{ Json::ValueType::objectValue };
|
||||
|
||||
std::set<std::string> _changeLog;
|
||||
|
||||
void _logSettingSet(const std::string_view& setting);
|
||||
|
||||
@@ -59,13 +59,16 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
||||
{
|
||||
auto globals{ winrt::make_self<GlobalAppSettings>() };
|
||||
|
||||
globals->_UnparsedDefaultProfile = _UnparsedDefaultProfile;
|
||||
|
||||
globals->_defaultProfile = _defaultProfile;
|
||||
globals->_actionMap = _actionMap->Copy();
|
||||
globals->_keybindingsWarnings = _keybindingsWarnings;
|
||||
globals->_json = _json;
|
||||
|
||||
// JSON-backed settings (UnparsedDefaultProfile, MTSM settings) all live in _json,
|
||||
// which is already deep-copied above. No per-setting copy needed.
|
||||
#define GLOBAL_SETTINGS_COPY(type, name, jsonKey, ...) \
|
||||
globals->_##name = _##name;
|
||||
MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_COPY)
|
||||
#undef GLOBAL_SETTINGS_COPY
|
||||
|
||||
if (_colorSchemes)
|
||||
{
|
||||
@@ -83,9 +86,6 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
||||
globals->_themes.Insert(kv.Key(), *themeImpl->Copy());
|
||||
}
|
||||
}
|
||||
|
||||
// Complex/mutable settings — backing fields for mutation lifecycle.
|
||||
// _json (copied above) is the source of truth; backing fields hold runtime state.
|
||||
if (_NewTabMenu)
|
||||
{
|
||||
globals->_NewTabMenu = winrt::single_threaded_vector<Model::NewTabMenuEntry>();
|
||||
@@ -94,6 +94,14 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::Copy() const
|
||||
globals->_NewTabMenu->Append(get_self<NewTabMenuEntry>(entry)->Copy());
|
||||
}
|
||||
}
|
||||
if (_DisabledProfileSources)
|
||||
{
|
||||
globals->_DisabledProfileSources = winrt::single_threaded_vector<hstring>();
|
||||
for (const auto& src : *_DisabledProfileSources)
|
||||
{
|
||||
globals->_DisabledProfileSources->Append(src);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& parent : _parents)
|
||||
{
|
||||
@@ -112,7 +120,7 @@ winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Microso
|
||||
void GlobalAppSettings::DefaultProfile(const winrt::guid& defaultProfile) noexcept
|
||||
{
|
||||
_defaultProfile = defaultProfile;
|
||||
UnparsedDefaultProfile(hstring{ Utils::GuidToString(defaultProfile) });
|
||||
_UnparsedDefaultProfile = Utils::GuidToString(defaultProfile);
|
||||
}
|
||||
|
||||
winrt::guid GlobalAppSettings::DefaultProfile() const
|
||||
@@ -142,46 +150,25 @@ winrt::com_ptr<GlobalAppSettings> GlobalAppSettings::FromJson(const Json::Value&
|
||||
|
||||
void GlobalAppSettings::LayerJson(const Json::Value& json, const OriginTag origin)
|
||||
{
|
||||
// Merge incoming JSON keys into stored _json (key-wise, not replacement).
|
||||
JsonUtils::MergeJsonKeys(json, _json);
|
||||
|
||||
// UnparsedDefaultProfile is now JSON-backed (in _json["defaultProfile"]).
|
||||
// No backing field to populate.
|
||||
JsonUtils::GetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
|
||||
|
||||
// GH#8076 - when adding enum values to this key, we also changed it from
|
||||
// "useTabSwitcher" to "tabSwitcherMode". Continue supporting
|
||||
// "useTabSwitcher", but prefer "tabSwitcherMode"
|
||||
// Normalize legacy keys into canonical _json keys for JSON-backed getters.
|
||||
static constexpr std::pair<std::string_view, std::string_view> legacyKeyMappings[] = {
|
||||
{ LegacyUseTabSwitcherModeKey, "tabSwitcherMode" },
|
||||
{ LegacyInputServiceWarningKey, "warning.inputService" },
|
||||
{ LegacyWarnAboutLargePasteKey, "warning.largePaste" },
|
||||
{ LegacyWarnAboutMultiLinePasteKey, "warning.multiLinePaste" },
|
||||
{ LegacyConfirmCloseAllTabsKey, "warning.confirmCloseAllTabs" },
|
||||
};
|
||||
for (const auto& [legacyKey, canonicalKey] : legacyKeyMappings)
|
||||
{
|
||||
if (json.isMember(JsonKey(legacyKey)))
|
||||
{
|
||||
_fixupsAppliedDuringLoad = true;
|
||||
_json[JsonKey(canonicalKey)] = json[JsonKey(legacyKey)];
|
||||
}
|
||||
}
|
||||
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyUseTabSwitcherModeKey, _TabSwitcherMode) || _fixupsAppliedDuringLoad;
|
||||
|
||||
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyInputServiceWarningKey, _InputServiceWarning) || _fixupsAppliedDuringLoad;
|
||||
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyWarnAboutLargePasteKey, _WarnAboutLargePaste) || _fixupsAppliedDuringLoad;
|
||||
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyWarnAboutMultiLinePasteKey, _WarnAboutMultiLinePaste) || _fixupsAppliedDuringLoad;
|
||||
_fixupsAppliedDuringLoad = JsonUtils::GetValueForKey(json, LegacyConfirmCloseAllTabsKey, _ConfirmCloseAllTabs) || _fixupsAppliedDuringLoad;
|
||||
|
||||
// MTSM settings are now JSON-backed (no backing fields).
|
||||
// Values are already in _json from the merge step above.
|
||||
// We only need to log which settings were set in this layer.
|
||||
#define GLOBAL_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
|
||||
_logSettingIfSet(jsonKey, json.isMember(jsonKey) && !json[jsonKey].isNull());
|
||||
JsonUtils::GetValueForKey(json, jsonKey, _##name); \
|
||||
_logSettingIfSet(jsonKey, _##name.has_value());
|
||||
|
||||
MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_LAYER_JSON)
|
||||
#undef GLOBAL_SETTINGS_LAYER_JSON
|
||||
|
||||
// Complex/mutable settings — backing fields populated from _json for runtime use.
|
||||
// _json is the source of truth for serialization; backing fields are for mutation lifecycle.
|
||||
JsonUtils::GetValueForKey(json, "newTabMenu", _NewTabMenu);
|
||||
_logSettingIfSet("newTabMenu", _NewTabMenu.has_value());
|
||||
|
||||
// GH#11975 We only want to allow sensible values and prevent crashes, so we are clamping those values
|
||||
// We only want to assign if the value did change through clamping,
|
||||
// otherwise we could end up setting defaults that get persisted
|
||||
@@ -317,105 +304,47 @@ Json::Value GlobalAppSettings::ToJson()
|
||||
// These experimental options should be removed from the settings file if they're at their default value.
|
||||
// This prevents them from sticking around forever, even if the user was just experimenting with them.
|
||||
// One could consider this a workaround for the settings UI right now not having a "reset to default" button for these.
|
||||
if (HasGraphicsAPI() && GraphicsAPI() == Control::GraphicsAPI::Automatic)
|
||||
if (_GraphicsAPI == Control::GraphicsAPI::Automatic)
|
||||
{
|
||||
ClearGraphicsAPI();
|
||||
_GraphicsAPI.reset();
|
||||
}
|
||||
if (HasTextMeasurement() && TextMeasurement() == Control::TextMeasurement::Graphemes)
|
||||
if (_TextMeasurement == Control::TextMeasurement::Graphemes)
|
||||
{
|
||||
ClearTextMeasurement();
|
||||
_TextMeasurement.reset();
|
||||
}
|
||||
if (HasAmbiguousWidth() && AmbiguousWidth() == Control::AmbiguousWidth::Narrow)
|
||||
if (_AmbiguousWidth == Control::AmbiguousWidth::Narrow)
|
||||
{
|
||||
ClearAmbiguousWidth();
|
||||
_AmbiguousWidth.reset();
|
||||
}
|
||||
if (HasDefaultInputScope() && DefaultInputScope() == Control::DefaultInputScope::Default)
|
||||
if (_DefaultInputScope == Control::DefaultInputScope::Default)
|
||||
{
|
||||
ClearDefaultInputScope();
|
||||
_DefaultInputScope.reset();
|
||||
}
|
||||
|
||||
if (HasDisablePartialInvalidation() && DisablePartialInvalidation() == false)
|
||||
if (_DisablePartialInvalidation == false)
|
||||
{
|
||||
ClearDisablePartialInvalidation();
|
||||
_DisablePartialInvalidation.reset();
|
||||
}
|
||||
if (HasSoftwareRendering() && SoftwareRendering() == false)
|
||||
if (_SoftwareRendering == false)
|
||||
{
|
||||
ClearSoftwareRendering();
|
||||
_SoftwareRendering.reset();
|
||||
}
|
||||
|
||||
Json::Value json{ Json::ValueType::objectValue };
|
||||
|
||||
// DefaultProfile: copy from _json
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, DefaultProfileKey);
|
||||
JsonUtils::SetValueForKey(json, DefaultProfileKey, _UnparsedDefaultProfile);
|
||||
|
||||
// MTSM global settings: copy from _json (the source of truth)
|
||||
#define GLOBAL_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, jsonKey);
|
||||
JsonUtils::SetValueForKey(json, jsonKey, _##name);
|
||||
MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_TO_JSON)
|
||||
#undef GLOBAL_SETTINGS_TO_JSON
|
||||
|
||||
// Complex/mutable settings — read from _json (source of truth), not backing fields
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, "newTabMenu");
|
||||
|
||||
json[JsonKey(ActionsKey)] = _actionMap->ToJson();
|
||||
json[JsonKey(KeybindingsKey)] = _actionMap->KeyBindingsToJson();
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
bool GlobalAppSettings::HasSetting(GlobalSettingKey key) const
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
#define _GLOBAL_HAS_SETTING(type, name, jsonKey, ...) \
|
||||
case GlobalSettingKey::name: \
|
||||
return Has##name();
|
||||
MTSM_GLOBAL_SETTINGS(_GLOBAL_HAS_SETTING)
|
||||
#undef _GLOBAL_HAS_SETTING
|
||||
case GlobalSettingKey::_UnparsedDefaultProfile:
|
||||
return HasUnparsedDefaultProfile();
|
||||
case GlobalSettingKey::_NewTabMenu:
|
||||
return HasNewTabMenu();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalAppSettings::ClearSetting(GlobalSettingKey key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
#define _GLOBAL_CLEAR_SETTING(type, name, jsonKey, ...) \
|
||||
case GlobalSettingKey::name: \
|
||||
Clear##name(); \
|
||||
break;
|
||||
MTSM_GLOBAL_SETTINGS(_GLOBAL_CLEAR_SETTING)
|
||||
#undef _GLOBAL_CLEAR_SETTING
|
||||
case GlobalSettingKey::_UnparsedDefaultProfile:
|
||||
ClearUnparsedDefaultProfile();
|
||||
break;
|
||||
case GlobalSettingKey::_NewTabMenu:
|
||||
ClearNewTabMenu();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<GlobalSettingKey> GlobalAppSettings::CurrentSettings() const
|
||||
{
|
||||
std::vector<GlobalSettingKey> result;
|
||||
for (auto i = 0; i < static_cast<int>(GlobalSettingKey::SETTINGS_SIZE); i++)
|
||||
{
|
||||
const auto key = static_cast<GlobalSettingKey>(i);
|
||||
if (HasSetting(key))
|
||||
{
|
||||
result.push_back(key);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GlobalAppSettings::FixupsAppliedDuringLoad()
|
||||
{
|
||||
return _fixupsAppliedDuringLoad || _actionMap->FixupsAppliedDuringLoad();
|
||||
@@ -465,9 +394,9 @@ bool GlobalAppSettings::ShouldUsePersistedLayout() const
|
||||
void GlobalAppSettings::ResolveMediaResources(const Model::MediaResourceResolver& resolver)
|
||||
{
|
||||
_actionMap->ResolveMediaResourcesWithBasePath(SourceBasePath, resolver);
|
||||
if (HasNewTabMenu())
|
||||
if (_NewTabMenu)
|
||||
{
|
||||
for (const auto& entry : NewTabMenu())
|
||||
for (const auto& entry : *_NewTabMenu)
|
||||
{
|
||||
if (const auto resolvable{ entry.try_as<IPathlessMediaResourceContainer>() })
|
||||
{
|
||||
@@ -485,12 +414,11 @@ void GlobalAppSettings::_logSettingSet(const std::string_view& setting)
|
||||
{
|
||||
if (setting == "theme")
|
||||
{
|
||||
if (HasTheme())
|
||||
if (_Theme.has_value())
|
||||
{
|
||||
const auto theme = Theme();
|
||||
// ThemePair always has a Dark/Light value,
|
||||
// so we need to check if they were explicitly set
|
||||
if (theme.DarkName() == theme.LightName())
|
||||
if (_Theme->DarkName() == _Theme->LightName())
|
||||
{
|
||||
_changeLog.emplace(setting);
|
||||
}
|
||||
@@ -503,9 +431,9 @@ void GlobalAppSettings::_logSettingSet(const std::string_view& setting)
|
||||
}
|
||||
else if (setting == "newTabMenu")
|
||||
{
|
||||
if (HasNewTabMenu())
|
||||
if (_NewTabMenu.has_value())
|
||||
{
|
||||
for (const auto& entry : NewTabMenu())
|
||||
for (const auto& entry : *_NewTabMenu)
|
||||
{
|
||||
std::string entryType;
|
||||
switch (entry.Type())
|
||||
@@ -548,7 +476,7 @@ void GlobalAppSettings::UpdateCommandID(const Model::Command& cmd, winrt::hstrin
|
||||
_actionMap->UpdateCommandID(cmd, newID);
|
||||
// newID might have been empty when this function was called, if so actionMap would have generated a new ID, use that
|
||||
newID = cmd.ID();
|
||||
if (HasNewTabMenu())
|
||||
if (_NewTabMenu)
|
||||
{
|
||||
// Recursive lambda function to look through all the new tab menu entries and update IDs accordingly
|
||||
std::function<void(const Model::NewTabMenuEntry&)> recursiveEntryIdUpdate;
|
||||
@@ -575,7 +503,7 @@ void GlobalAppSettings::UpdateCommandID(const Model::Command& cmd, winrt::hstrin
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto& entry : NewTabMenu())
|
||||
for (const auto& entry : *_NewTabMenu)
|
||||
{
|
||||
recursiveEntryIdUpdate(entry);
|
||||
}
|
||||
@@ -587,8 +515,8 @@ void GlobalAppSettings::_logSettingIfSet(const std::string_view& setting, const
|
||||
if (isSet)
|
||||
{
|
||||
// Exclude some false positives from userDefaults.json
|
||||
const bool settingCopyFormattingToDefault = til::equals_insensitive_ascii(setting, "copyFormatting") && HasCopyFormatting() && CopyFormatting() == static_cast<Control::CopyFormat>(0);
|
||||
const bool settingNTMToDefault = til::equals_insensitive_ascii(setting, "newTabMenu") && HasNewTabMenu() && NewTabMenu().Size() == 1 && NewTabMenu().GetAt(0).Type() == NewTabMenuEntryType::RemainingProfiles;
|
||||
const bool settingCopyFormattingToDefault = til::equals_insensitive_ascii(setting, "copyFormatting") && _CopyFormatting.has_value() && _CopyFormatting.value() == static_cast<Control::CopyFormat>(0);
|
||||
const bool settingNTMToDefault = til::equals_insensitive_ascii(setting, "newTabMenu") && _NewTabMenu.has_value() && _NewTabMenu->Size() == 1 && _NewTabMenu->GetAt(0).Type() == NewTabMenuEntryType::RemainingProfiles;
|
||||
if (!settingCopyFormattingToDefault && !settingNTMToDefault)
|
||||
{
|
||||
_logSettingSet(setting);
|
||||
|
||||
@@ -18,7 +18,6 @@ Author(s):
|
||||
#include "GlobalAppSettings.g.h"
|
||||
#include "IInheritable.h"
|
||||
#include "MTSMSettings.h"
|
||||
#include "TerminalSettingsSerializationHelpers.h"
|
||||
|
||||
#include "ActionMap.h"
|
||||
#include "Command.h"
|
||||
@@ -57,11 +56,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
Json::Value ToJson();
|
||||
bool FixupsAppliedDuringLoad();
|
||||
|
||||
// Generic setting access via SettingKey
|
||||
bool HasSetting(GlobalSettingKey key) const;
|
||||
void ClearSetting(GlobalSettingKey key);
|
||||
std::vector<GlobalSettingKey> CurrentSettings() const;
|
||||
|
||||
const std::vector<SettingsLoadWarnings>& KeybindingsWarnings() const;
|
||||
|
||||
// This DefaultProfile() setter is called by CascadiaSettings,
|
||||
@@ -86,28 +80,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
|
||||
winrt::hstring SourceBasePath;
|
||||
|
||||
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, UnparsedDefaultProfile, "defaultProfile", L"");
|
||||
INHERITABLE_SETTING(Model::GlobalAppSettings, hstring, UnparsedDefaultProfile, L"");
|
||||
|
||||
#define GLOBAL_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
|
||||
INHERITABLE_SETTING_WITH_LOGGING(Model::GlobalAppSettings, type, name, jsonKey, ##__VA_ARGS__)
|
||||
MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_INITIALIZE)
|
||||
#undef GLOBAL_SETTINGS_INITIALIZE
|
||||
|
||||
// NewTabMenu: mutable with backing field for editor in-place mutation.
|
||||
// _json is the source of truth for serialization. Setter dual-writes to both.
|
||||
_BASE_INHERITABLE_MUTABLE_SETTING(Model::GlobalAppSettings, std::optional<winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry>>, NewTabMenu, winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} }))
|
||||
public:
|
||||
winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry> NewTabMenu() const
|
||||
{
|
||||
const auto val{ _getNewTabMenuImpl() };
|
||||
return val ? *val : winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} });
|
||||
}
|
||||
void NewTabMenu(const winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry>& value)
|
||||
{
|
||||
_NewTabMenu = value;
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::SetValueForKey(_json, "newTabMenu", value);
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef NDEBUG
|
||||
static constexpr bool debugFeaturesDefault{ false };
|
||||
@@ -115,10 +94,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
static constexpr bool debugFeaturesDefault{ true };
|
||||
#endif
|
||||
|
||||
// Raw JSON for this layer. Populated by LayerJson(), will become the
|
||||
// source of truth for settings once the JSON-backed refactor is complete.
|
||||
Json::Value _json{ Json::ValueType::objectValue };
|
||||
|
||||
winrt::guid _defaultProfile{};
|
||||
bool _fixupsAppliedDuringLoad{ false };
|
||||
bool _legacyReloadEnvironmentVariables{ true };
|
||||
|
||||
@@ -14,8 +14,6 @@ Author(s):
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "JsonUtils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
template<typename T>
|
||||
@@ -81,554 +79,189 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
using NullableSetting = std::optional<std::optional<T>>;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Inheritable setting macros
|
||||
// =============================================================================
|
||||
//
|
||||
// These macros implement the standard functions for inheritable settings:
|
||||
// - Has<NAME>(): checks if the user explicitly set a value for this setting
|
||||
// - <NAME>OverrideSource(): returns the object that provides the resolved value
|
||||
// - Getter(): returns the resolved value (this layer --> parent --> default)
|
||||
// - Setter(): sets the value
|
||||
// - Clear<NAME>(): clears the user set value (reverts to inherited/default)
|
||||
//
|
||||
// There are two storage strategies:
|
||||
//
|
||||
// 1. JSON-backed (preferred): All state lives in _json (a Json::Value member).
|
||||
// Use these for any setting with a ConversionTrait. The owning class must
|
||||
// declare a `Json::Value _json{ Json::ValueType::objectValue };` member.
|
||||
//
|
||||
// 2. Mutable backing-field (exception): State lives in a std::optional<T> member.
|
||||
// Use these only for types that callers mutate in place after retrieval, such
|
||||
// as IMediaResource (resolved via ResolveMediaResources), IVector, and IMap.
|
||||
// A JSON-backed getter would deserialize a fresh copy on each call, losing
|
||||
// those in-place mutations.
|
||||
//
|
||||
// When adding a new setting, use the JSON-backed macros unless the type requires
|
||||
// in-place mutation. Existing backing-field settings should be migrated to
|
||||
// JSON-backed as their mutation patterns are resolved.
|
||||
//
|
||||
// Available macros (JSON-backed):
|
||||
// INHERITABLE_SETTING(projectedType, type, name, jsonKey, ...)
|
||||
// INHERITABLE_SETTING_WITH_LOGGING(projectedType, type, name, jsonKey, ...)
|
||||
// INHERITABLE_NULLABLE_SETTING(projectedType, type, name, jsonKey, ...)
|
||||
// _BASE_INHERITABLE_SETTING(projectedType, type, name, jsonKey, ...)
|
||||
//
|
||||
// Available macros (mutable backing-field):
|
||||
// INHERITABLE_MUTABLE_SETTING(projectedType, type, name, ...)
|
||||
// INHERITABLE_NULLABLE_MUTABLE_SETTING(projectedType, type, name, ...)
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
// =============================================================================
|
||||
// JSON-backed inheritable settings
|
||||
// =============================================================================
|
||||
// No std::optional<T> backing field — _json is the source of truth.
|
||||
// Getters deserialize from _json via ConversionTrait on each call.
|
||||
// Setters serialize to _json via SetValueForKey.
|
||||
// Has/Clear check/modify _json directly.
|
||||
|
||||
// Shared base for JSON-backed inheritable settings.
|
||||
// Provides Has, Clear, OverrideSource, and the private implementation helpers.
|
||||
// Does NOT provide the public getter/setter — use INHERITABLE_SETTING or
|
||||
// INHERITABLE_SETTING_WITH_LOGGING which add those on top of this base.
|
||||
#define _BASE_INHERITABLE_SETTING(projectedType, type, name, jsonKey, ...) \
|
||||
public: \
|
||||
/* Returns true if the user explicitly set the value, false otherwise */ \
|
||||
bool Has##name() const \
|
||||
{ \
|
||||
return _json.isMember(jsonKey) && !_json[jsonKey].isNull(); \
|
||||
} \
|
||||
\
|
||||
/* Returns the object that provides the resolved value */ \
|
||||
projectedType name##OverrideSource() \
|
||||
{ \
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return *source; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no source was found*/ \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
/* Clear the user set value */ \
|
||||
void Clear##name() \
|
||||
{ \
|
||||
_json.removeMember(JsonKey(jsonKey)); \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
/* Read value from this layer's _json only (no parent walk) */ \
|
||||
std::optional<type> _get##name##FromThisLayer() const \
|
||||
{ \
|
||||
if (Has##name()) \
|
||||
{ \
|
||||
type val{ __VA_ARGS__ }; \
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::GetValueForKey( \
|
||||
_json, jsonKey, val); \
|
||||
return val; \
|
||||
} \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
\
|
||||
/* Resolve the value: this layer --> parents --> nullopt */ \
|
||||
std::optional<type> _get##name##Impl() const \
|
||||
{ \
|
||||
/*return value from this layer*/ \
|
||||
if (auto val{ _get##name##FromThisLayer() }) \
|
||||
{ \
|
||||
return val; \
|
||||
} \
|
||||
\
|
||||
/*iterate through parents to find a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto val{ parent->_get##name##Impl() }) \
|
||||
{ \
|
||||
return val; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
\
|
||||
/* Find the object that provides the resolved value */ \
|
||||
auto _get##name##OverrideSourceImpl()->decltype(get_strong()) \
|
||||
{ \
|
||||
/*we have a value*/ \
|
||||
if (Has##name()) \
|
||||
{ \
|
||||
return get_strong(); \
|
||||
} \
|
||||
\
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return source; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
/* Find the override source and the value it provides */ \
|
||||
auto _get##name##OverrideSourceAndValueImpl() \
|
||||
->std::pair<decltype(get_strong()), std::optional<type>> \
|
||||
{ \
|
||||
/*we have a value*/ \
|
||||
if (Has##name()) \
|
||||
{ \
|
||||
return { get_strong(), _get##name##FromThisLayer() }; \
|
||||
} \
|
||||
\
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return { source, source->_get##name##FromThisLayer() }; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return { nullptr, std::nullopt }; \
|
||||
// Shared implementation between the INHERITABLE_SETTING and INHERITABLE_NULLABLE_SETTING macros.
|
||||
// See below for more details.
|
||||
#define _BASE_INHERITABLE_SETTING(projectedType, storageType, name, ...) \
|
||||
public: \
|
||||
/* Returns true if the user explicitly set the value, false otherwise*/ \
|
||||
bool Has##name() const \
|
||||
{ \
|
||||
return _##name.has_value(); \
|
||||
} \
|
||||
\
|
||||
projectedType name##OverrideSource() \
|
||||
{ \
|
||||
/*user set value was not set*/ \
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return *source; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no source was found*/ \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
/* Clear the user set value */ \
|
||||
void Clear##name() \
|
||||
{ \
|
||||
_##name = std::nullopt; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
storageType _##name{ std::nullopt }; \
|
||||
\
|
||||
storageType _get##name##Impl() const \
|
||||
{ \
|
||||
/*return user set value*/ \
|
||||
if (_##name) \
|
||||
{ \
|
||||
return _##name; \
|
||||
} \
|
||||
\
|
||||
/*user set value was not set*/ \
|
||||
/*iterate through parents to find a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto val{ parent->_get##name##Impl() }) \
|
||||
{ \
|
||||
return val; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
\
|
||||
auto _get##name##OverrideSourceImpl()->decltype(get_strong()) \
|
||||
{ \
|
||||
/*we have a value*/ \
|
||||
if (_##name) \
|
||||
{ \
|
||||
return get_strong(); \
|
||||
} \
|
||||
\
|
||||
/*user set value was not set*/ \
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return source; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
auto _get##name##OverrideSourceAndValueImpl() \
|
||||
->std::pair<decltype(get_strong()), storageType> \
|
||||
{ \
|
||||
/*we have a value*/ \
|
||||
if (_##name) \
|
||||
{ \
|
||||
return { get_strong(), _##name }; \
|
||||
} \
|
||||
\
|
||||
/*user set value was not set*/ \
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return { source, source->_##name }; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return { nullptr, std::nullopt }; \
|
||||
}
|
||||
|
||||
// JSON-backed inheritable setting.
|
||||
// Getter returns the resolved value: this layer --> inherited --> default.
|
||||
// Setter writes the value to _json.
|
||||
#define INHERITABLE_SETTING(projectedType, type, name, jsonKey, ...) \
|
||||
_BASE_INHERITABLE_SETTING(projectedType, type, name, jsonKey, __VA_ARGS__) \
|
||||
public: \
|
||||
/* Returns the resolved value for this setting */ \
|
||||
/* fallback: this layer --> inherited value --> default */ \
|
||||
type name() const \
|
||||
{ \
|
||||
const auto val{ _get##name##Impl() }; \
|
||||
return val ? *val : type{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Overwrite the user set value in _json */ \
|
||||
void name(const type& value) \
|
||||
{ \
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::SetValueForKey( \
|
||||
_json, jsonKey, value); \
|
||||
// Use INHERITABLE_SETTING and INHERITABLE_NULLABLE_SETTING to implement
|
||||
// standard functions for inheritable settings. This is similar to the WINRT_PROPERTY macro,
|
||||
// except...
|
||||
// - Has<NAME>(): checks if the user explicitly set a value for this setting
|
||||
// - <NAME>OverrideSource(): return the object that provides the resolved value
|
||||
// - Getter(): return the resolved value
|
||||
// - Setter(): set the value directly
|
||||
// - Clear(): clear the user set value
|
||||
// - the setting is saved as an optional, where nullopt means
|
||||
// that we must inherit the value from our parent
|
||||
#define INHERITABLE_SETTING(projectedType, type, name, ...) \
|
||||
_BASE_INHERITABLE_SETTING(projectedType, std::optional<type>, name, ...) \
|
||||
public: \
|
||||
/* Returns the resolved value for this setting */ \
|
||||
/* fallback: user set value --> inherited value --> system set value */ \
|
||||
type name() const \
|
||||
{ \
|
||||
const auto val{ _get##name##Impl() }; \
|
||||
return val ? *val : type{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Overwrite the user set value */ \
|
||||
void name(const type& value) \
|
||||
{ \
|
||||
_##name = value; \
|
||||
}
|
||||
|
||||
// JSON-backed inheritable setting with change logging.
|
||||
// Same as INHERITABLE_SETTING, but the setter also calls _logSettingSet(jsonKey)
|
||||
// when the value actually changes (for settings change telemetry).
|
||||
#define INHERITABLE_SETTING_WITH_LOGGING(projectedType, type, name, jsonKey, ...) \
|
||||
_BASE_INHERITABLE_SETTING(projectedType, type, name, jsonKey, __VA_ARGS__) \
|
||||
public: \
|
||||
/* Returns the resolved value for this setting */ \
|
||||
/* fallback: this layer --> inherited value --> default */ \
|
||||
type name() const \
|
||||
{ \
|
||||
const auto val{ _get##name##Impl() }; \
|
||||
return val ? *val : type{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Overwrite the user set value, log the change, and write to _json */ \
|
||||
void name(const type& value) \
|
||||
{ \
|
||||
const auto existingVal{ _get##name##FromThisLayer() }; \
|
||||
if (!existingVal.has_value() || existingVal.value() != value) \
|
||||
{ \
|
||||
_logSettingSet(jsonKey); \
|
||||
} \
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::SetValueForKey( \
|
||||
_json, jsonKey, value); \
|
||||
#define INHERITABLE_SETTING_WITH_LOGGING(projectedType, type, name, jsonKey, ...) \
|
||||
_BASE_INHERITABLE_SETTING(projectedType, std::optional<type>, name, ...) \
|
||||
public: \
|
||||
/* Returns the resolved value for this setting */ \
|
||||
/* fallback: user set value --> inherited value --> system set value */ \
|
||||
type name() const \
|
||||
{ \
|
||||
const auto val{ _get##name##Impl() }; \
|
||||
return val ? *val : type{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Overwrite the user set value */ \
|
||||
void name(const type& value) \
|
||||
{ \
|
||||
if (!_##name.has_value() || _##name.value() != value) \
|
||||
{ \
|
||||
_logSettingSet(jsonKey); \
|
||||
} \
|
||||
_##name = value; \
|
||||
}
|
||||
|
||||
// JSON-backed nullable inheritable setting.
|
||||
// For settings where null is a valid explicit value (e.g., Foreground color).
|
||||
// Key absent → inherit from parent
|
||||
// Key present + null → explicitly "no value" (getter returns nullptr)
|
||||
// Key present + value → has a value
|
||||
// Getter returns IReference<T>.
|
||||
#define INHERITABLE_NULLABLE_SETTING(projectedType, type, name, jsonKey, ...) \
|
||||
public: \
|
||||
/* Key presence means explicitly set (even if value is null) */ \
|
||||
bool Has##name() const \
|
||||
{ \
|
||||
return _json.isMember(jsonKey); \
|
||||
} \
|
||||
\
|
||||
/* Returns the object that provides the resolved value */ \
|
||||
projectedType name##OverrideSource() \
|
||||
{ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return *source; \
|
||||
} \
|
||||
} \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
/* Clear the user set value (remove key entirely → inherit from parent) */ \
|
||||
void Clear##name() \
|
||||
{ \
|
||||
_json.removeMember(JsonKey(jsonKey)); \
|
||||
} \
|
||||
\
|
||||
/* Returns the resolved value for this setting */ \
|
||||
/* fallback: this layer --> inherited value --> default */ \
|
||||
winrt::Windows::Foundation::IReference<type> name() const \
|
||||
{ \
|
||||
const auto val{ _get##name##Impl() }; \
|
||||
if (val) \
|
||||
{ \
|
||||
if (*val) \
|
||||
{ \
|
||||
return **val; \
|
||||
} \
|
||||
return nullptr; \
|
||||
} \
|
||||
return winrt::Windows::Foundation::IReference<type>{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Overwrite the user set value in _json */ \
|
||||
void name(const winrt::Windows::Foundation::IReference<type>& value) \
|
||||
{ \
|
||||
if (value) \
|
||||
{ \
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::SetValueForKey( \
|
||||
_json, jsonKey, value.Value()); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/* explicitly set to null (not the same as clearing) */ \
|
||||
_json[JsonKey(jsonKey)] = Json::nullValue; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
/* Read nullable value from this layer's _json only (no parent walk) */ \
|
||||
/* Returns: nullopt = not set. optional{nullopt} = explicitly null. */ \
|
||||
/* optional{optional{val}} = has value. */ \
|
||||
NullableSetting<type> _get##name##FromThisLayer() const \
|
||||
{ \
|
||||
if (_json.isMember(jsonKey)) \
|
||||
{ \
|
||||
if (_json[jsonKey].isNull()) \
|
||||
{ \
|
||||
return std::optional<type>{ std::nullopt }; \
|
||||
} \
|
||||
type val{}; \
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::GetValueForKey( \
|
||||
_json, jsonKey, val); \
|
||||
return std::optional<type>{ val }; \
|
||||
} \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
\
|
||||
/* Resolve the nullable value: this layer --> parents --> nullopt */ \
|
||||
NullableSetting<type> _get##name##Impl() const \
|
||||
{ \
|
||||
if (auto val{ _get##name##FromThisLayer() }) \
|
||||
{ \
|
||||
return val; \
|
||||
} \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto val{ parent->_get##name##Impl() }) \
|
||||
{ \
|
||||
return val; \
|
||||
} \
|
||||
} \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
\
|
||||
/* Find the object that provides the resolved value */ \
|
||||
auto _get##name##OverrideSourceImpl()->decltype(get_strong()) \
|
||||
{ \
|
||||
if (Has##name()) \
|
||||
{ \
|
||||
return get_strong(); \
|
||||
} \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return source; \
|
||||
} \
|
||||
} \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
/* Find the override source and the value it provides */ \
|
||||
auto _get##name##OverrideSourceAndValueImpl() \
|
||||
->std::pair<decltype(get_strong()), NullableSetting<type>> \
|
||||
{ \
|
||||
if (Has##name()) \
|
||||
{ \
|
||||
return { get_strong(), _get##name##FromThisLayer() }; \
|
||||
} \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return { source, source->_get##name##FromThisLayer() }; \
|
||||
} \
|
||||
} \
|
||||
return { nullptr, std::nullopt }; \
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Mutable backing-field inheritable settings
|
||||
// =============================================================================
|
||||
// These use a std::optional<T> backing field instead of _json.
|
||||
//
|
||||
// Use these ONLY for types that callers mutate in place after retrieval.
|
||||
// A JSON-backed getter would deserialize a fresh copy on each call, so
|
||||
// in-place mutations (e.g. ResolveMediaResources) would be lost.
|
||||
//
|
||||
// Current uses:
|
||||
// Profile: Icon, EnvironmentVariables, BellSound, UnfocusedAppearance
|
||||
// GlobalAppSettings: DisabledProfileSources, NewTabMenu
|
||||
// AppearanceConfig: PixelShaderPath, PixelShaderImagePath, BackgroundImagePath,
|
||||
// DarkColorSchemeName, LightColorSchemeName
|
||||
// FontConfig: FontAxes, FontFeatures
|
||||
|
||||
// Shared base for backing-field inheritable settings.
|
||||
// Provides Has, Clear, OverrideSource, and the private implementation helpers.
|
||||
#define _BASE_INHERITABLE_MUTABLE_SETTING(projectedType, storageType, name, ...) \
|
||||
public: \
|
||||
/* Returns true if the user explicitly set the value, false otherwise */ \
|
||||
bool Has##name() const \
|
||||
{ \
|
||||
return _##name.has_value(); \
|
||||
} \
|
||||
\
|
||||
/* Returns the object that provides the resolved value */ \
|
||||
projectedType name##OverrideSource() \
|
||||
{ \
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return *source; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no source was found*/ \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
/* Clear the user set value */ \
|
||||
void Clear##name() \
|
||||
{ \
|
||||
_##name = std::nullopt; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
storageType _##name{ std::nullopt }; \
|
||||
\
|
||||
/* Resolve the value: this layer --> parents --> nullopt */ \
|
||||
storageType _get##name##Impl() const \
|
||||
{ \
|
||||
/*return user set value*/ \
|
||||
if (_##name) \
|
||||
{ \
|
||||
return _##name; \
|
||||
} \
|
||||
\
|
||||
/*iterate through parents to find a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto val{ parent->_get##name##Impl() }) \
|
||||
{ \
|
||||
return val; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return std::nullopt; \
|
||||
} \
|
||||
\
|
||||
/* Find the object that provides the resolved value */ \
|
||||
auto _get##name##OverrideSourceImpl()->decltype(get_strong()) \
|
||||
{ \
|
||||
/*we have a value*/ \
|
||||
if (_##name) \
|
||||
{ \
|
||||
return get_strong(); \
|
||||
} \
|
||||
\
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return source; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
/* Find the override source and the value it provides */ \
|
||||
auto _get##name##OverrideSourceAndValueImpl() \
|
||||
->std::pair<decltype(get_strong()), storageType> \
|
||||
{ \
|
||||
/*we have a value*/ \
|
||||
if (_##name) \
|
||||
{ \
|
||||
return { get_strong(), _##name }; \
|
||||
} \
|
||||
\
|
||||
/*iterate through parents to find one with a value*/ \
|
||||
for (const auto& parent : _parents) \
|
||||
{ \
|
||||
if (auto source{ parent->_get##name##OverrideSourceImpl() }) \
|
||||
{ \
|
||||
return { source, source->_##name }; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/*no value was found*/ \
|
||||
return { nullptr, std::nullopt }; \
|
||||
}
|
||||
|
||||
// Mutable backing-field setting.
|
||||
// Getter returns the resolved value: this layer --> inherited --> default.
|
||||
// Setter writes to the std::optional<T> backing field.
|
||||
#define INHERITABLE_MUTABLE_SETTING(projectedType, type, name, ...) \
|
||||
_BASE_INHERITABLE_MUTABLE_SETTING(projectedType, std::optional<type>, name, ...) \
|
||||
public: \
|
||||
/* Returns the resolved value for this setting */ \
|
||||
/* fallback: this layer --> inherited value --> default */ \
|
||||
type name() const \
|
||||
{ \
|
||||
const auto val{ _get##name##Impl() }; \
|
||||
return val ? *val : type{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Overwrite the user set value */ \
|
||||
void name(const type& value) \
|
||||
{ \
|
||||
_##name = value; \
|
||||
}
|
||||
|
||||
// Mutable nullable backing-field setting.
|
||||
// Same as INHERITABLE_MUTABLE_SETTING, but for optional settings where null is
|
||||
// a valid explicit value. Getter returns IReference<T>.
|
||||
#define INHERITABLE_NULLABLE_MUTABLE_SETTING(projectedType, type, name, ...) \
|
||||
_BASE_INHERITABLE_MUTABLE_SETTING(projectedType, NullableSetting<type>, name, ...) \
|
||||
public: \
|
||||
/* Returns the resolved value for this setting */ \
|
||||
/* fallback: this layer --> inherited value --> default */ \
|
||||
winrt::Windows::Foundation::IReference<type> name() const \
|
||||
{ \
|
||||
const auto val{ _get##name##Impl() }; \
|
||||
if (val) \
|
||||
{ \
|
||||
if (*val) \
|
||||
{ \
|
||||
return **val; \
|
||||
} \
|
||||
return nullptr; \
|
||||
} \
|
||||
return winrt::Windows::Foundation::IReference<type>{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Overwrite the user set value */ \
|
||||
void name(const winrt::Windows::Foundation::IReference<type>& value) \
|
||||
{ \
|
||||
if (value) \
|
||||
{ \
|
||||
_##name = std::optional<type>{ value.Value() }; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/* explicitly set to null (not the same as clearing) */ \
|
||||
_##name = std::optional<type>{ std::nullopt }; \
|
||||
} \
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// IMediaResource settings with backing fields for resolution lifecycle.
|
||||
// =============================================================================
|
||||
//
|
||||
// Use for settings of type IMediaResource that need in-place resolution
|
||||
// (e.g., Icon, PixelShaderPath, BackgroundImagePath). The backing field
|
||||
// holds the runtime-resolved object. _json is the source of truth for
|
||||
// serialization. The setter dual-writes to both.
|
||||
//
|
||||
// Parameters:
|
||||
// projectedType - the WinRT projected type (e.g., Model::Profile)
|
||||
// name - the setting name (e.g., Icon)
|
||||
// jsonKey - the JSON key (e.g., "icon")
|
||||
// ... - default value (e.g., implementation::MediaResource::Empty())
|
||||
//
|
||||
#define INHERITABLE_MEDIA_RESOURCE_SETTING(projectedType, name, jsonKey, ...) \
|
||||
_BASE_INHERITABLE_MUTABLE_SETTING(projectedType, std::optional<IMediaResource>, name, \
|
||||
implementation::MediaResource::Empty()) \
|
||||
public: \
|
||||
/* Returns the resolved value: this layer --> inherited --> default */ \
|
||||
IMediaResource name() const \
|
||||
{ \
|
||||
const auto v{ _get##name##Impl() }; \
|
||||
return v ? *v : IMediaResource{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Dual-write: backing field (for resolution) + _json (for serialization) */ \
|
||||
void name(const IMediaResource& value) \
|
||||
{ \
|
||||
_##name = value; \
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::SetValueForKey(_json, jsonKey, value); \
|
||||
// This macro is similar to the one above, but is reserved for optional settings
|
||||
// like Profile.Foreground (where null is interpreted
|
||||
// as an acceptable value, rather than "inherit")
|
||||
// "type" is exposed as an IReference
|
||||
#define INHERITABLE_NULLABLE_SETTING(projectedType, type, name, ...) \
|
||||
_BASE_INHERITABLE_SETTING(projectedType, NullableSetting<type>, name, ...) \
|
||||
public: \
|
||||
/* Returns the resolved value for this setting */ \
|
||||
/* fallback: user set value --> inherited value --> system set value */ \
|
||||
winrt::Windows::Foundation::IReference<type> name() const \
|
||||
{ \
|
||||
const auto val{ _get##name##Impl() }; \
|
||||
if (val) \
|
||||
{ \
|
||||
if (*val) \
|
||||
{ \
|
||||
return **val; \
|
||||
} \
|
||||
return nullptr; \
|
||||
} \
|
||||
return winrt::Windows::Foundation::IReference<type>{ __VA_ARGS__ }; \
|
||||
} \
|
||||
\
|
||||
/* Overwrite the user set value */ \
|
||||
void name(const winrt::Windows::Foundation::IReference<type>& value) \
|
||||
{ \
|
||||
if (value) /*set value is different*/ \
|
||||
{ \
|
||||
_##name = std::optional<type>{ value.Value() }; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/* note we're setting the _inner_ value */ \
|
||||
_##name = std::optional<type>{ std::nullopt }; \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -250,28 +250,6 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
|
||||
SetValueForKey(json, key, target, ConversionTrait<std::decay_t<T>>{});
|
||||
}
|
||||
|
||||
// CopyKeyIfPresent: copies a key's raw Json::Value from source to target
|
||||
// if it exists in source. No type conversion — just raw JSON copy.
|
||||
// Used in ToJson() to copy JSON-backed settings from _json to output.
|
||||
inline void CopyKeyIfPresent(const Json::Value& source, Json::Value& target, const std::string_view key)
|
||||
{
|
||||
if (source.isMember(JsonKey(key)))
|
||||
{
|
||||
target[JsonKey(key)] = source[JsonKey(key)];
|
||||
}
|
||||
}
|
||||
|
||||
// MergeJsonKeys: copies all keys from source into target (key-wise merge).
|
||||
// Existing keys in target are overwritten by source values.
|
||||
// Used in LayerJson() to merge incoming JSON into stored _json.
|
||||
inline void MergeJsonKeys(const Json::Value& source, Json::Value& target)
|
||||
{
|
||||
for (const auto& key : source.getMemberNames())
|
||||
{
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
struct ConversionTrait<std::string>
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@ Module Name:
|
||||
Abstract:
|
||||
- Contains most of the settings within Terminal Settings Model (global, profile, font, appearance)
|
||||
- To add a new setting to any one of those classes, simply add it to the respective list below, following the macro format
|
||||
- Also defines SettingKey enums for generic setting access
|
||||
|
||||
Author(s):
|
||||
- Pankaj Bhojwani - October 2021
|
||||
@@ -63,15 +62,16 @@ Author(s):
|
||||
X(Model::WindowingMode, WindowingBehavior, "windowingBehavior", Model::WindowingMode::UseNew) \
|
||||
X(bool, MinimizeToNotificationArea, "minimizeToNotificationArea", false) \
|
||||
X(bool, AlwaysShowNotificationIcon, "alwaysShowNotificationIcon", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, "disabledProfileSources", nullptr) \
|
||||
X(bool, ShowAdminShield, "showAdminShield", true) \
|
||||
X(bool, TrimPaste, "trimPaste", true) \
|
||||
X(bool, EnableColorSelection, "experimental.enableColorSelection", false) \
|
||||
X(bool, EnableShellCompletionMenu, "experimental.enableShellCompletionMenu", false) \
|
||||
X(bool, EnableUnfocusedAcrylic, "compatibility.enableUnfocusedAcrylic", true) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<Model::NewTabMenuEntry>, NewTabMenu, "newTabMenu", winrt::single_threaded_vector<Model::NewTabMenuEntry>({ Model::RemainingProfilesEntry{} })) \
|
||||
X(bool, AllowHeadless, "compatibility.allowHeadless", false) \
|
||||
X(hstring, SearchWebDefaultQueryUrl, "searchWebDefaultQueryUrl", L"https://www.bing.com/search?q=%22%s%22") \
|
||||
X(bool, ShowTabsFullscreen, "showTabsFullscreen", false) \
|
||||
X(winrt::Windows::Foundation::Collections::IVector<winrt::hstring>, DisabledProfileSources, "disabledProfileSources", nullptr)
|
||||
X(bool, ShowTabsFullscreen, "showTabsFullscreen", false)
|
||||
|
||||
// Also add these settings to:
|
||||
// * Profile.idl
|
||||
@@ -88,12 +88,15 @@ Author(s):
|
||||
X(Microsoft::Terminal::Control::ScrollbarState, ScrollState, "scrollbarState", Microsoft::Terminal::Control::ScrollbarState::Visible) \
|
||||
X(Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode, "antialiasingMode", Microsoft::Terminal::Control::TextAntialiasingMode::Grayscale) \
|
||||
X(hstring, StartingDirectory, "startingDirectory") \
|
||||
X(IMediaResource, Icon, "icon", implementation::MediaResource::FromString(L"\uE756")) \
|
||||
X(bool, SuppressApplicationTitle, "suppressApplicationTitle", false) \
|
||||
X(guid, ConnectionType, "connectionType") \
|
||||
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Automatic) \
|
||||
X(hstring, TabTitle, "tabTitle") \
|
||||
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
|
||||
X(IEnvironmentVariableMap, EnvironmentVariables, "environment", nullptr) \
|
||||
X(bool, RightClickContextMenu, "rightClickContextMenu", false) \
|
||||
X(Windows::Foundation::Collections::IVector<IMediaResource>, BellSound, "bellSound", nullptr) \
|
||||
X(bool, Elevate, "elevate", false) \
|
||||
X(bool, AutoMarkPrompts, "autoMarkPrompts", true) \
|
||||
X(bool, ShowMarks, "showMarksOnScrollbar", false) \
|
||||
@@ -105,9 +108,7 @@ Author(s):
|
||||
X(bool, AllowVtChecksumReport, "compatibility.allowDECRQCRA", false) \
|
||||
X(bool, AllowVtClipboardWrite, "compatibility.allowOSC52", true) \
|
||||
X(bool, AllowKeypadMode, "compatibility.allowDECNKM", false) \
|
||||
X(hstring, DragDropDelimiter, "dragDropDelimiter", L" ") \
|
||||
X(Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, "pathTranslationStyle", Microsoft::Terminal::Control::PathTranslationStyle::None) \
|
||||
X(IEnvironmentVariableMap, EnvironmentVariables, "environment", nullptr)
|
||||
X(Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, "pathTranslationStyle", Microsoft::Terminal::Control::PathTranslationStyle::None)
|
||||
|
||||
// Intentionally omitted Profile settings:
|
||||
// * Name
|
||||
@@ -122,12 +123,12 @@ Author(s):
|
||||
X(hstring, FontFace, "face", DEFAULT_FONT_FACE) \
|
||||
X(float, FontSize, "size", DEFAULT_FONT_SIZE) \
|
||||
X(winrt::Windows::UI::Text::FontWeight, FontWeight, "weight", DEFAULT_FONT_WEIGHT) \
|
||||
X(IFontAxesMap, FontAxes, "axes") \
|
||||
X(IFontFeatureMap, FontFeatures, "features") \
|
||||
X(bool, EnableBuiltinGlyphs, "builtinGlyphs", true) \
|
||||
X(bool, EnableColorGlyphs, "colorGlyphs", true) \
|
||||
X(winrt::hstring, CellWidth, "cellWidth") \
|
||||
X(winrt::hstring, CellHeight, "cellHeight") \
|
||||
X(IFontAxesMap, FontAxes, "axes") \
|
||||
X(IFontFeatureMap, FontFeatures, "features")
|
||||
X(winrt::hstring, CellHeight, "cellHeight")
|
||||
|
||||
#define MTSM_APPEARANCE_SETTINGS(X) \
|
||||
X(Core::CursorStyle, CursorShape, "cursorShape", Core::CursorStyle::Bar) \
|
||||
@@ -135,7 +136,10 @@ Author(s):
|
||||
X(float, BackgroundImageOpacity, "backgroundImageOpacity", 1.0f) \
|
||||
X(winrt::Windows::UI::Xaml::Media::Stretch, BackgroundImageStretchMode, "backgroundImageStretchMode", winrt::Windows::UI::Xaml::Media::Stretch::UniformToFill) \
|
||||
X(bool, RetroTerminalEffect, "experimental.retroTerminalEffect", false) \
|
||||
X(IMediaResource, PixelShaderPath, "experimental.pixelShaderPath", implementation::MediaResource::Empty()) \
|
||||
X(IMediaResource, PixelShaderImagePath, "experimental.pixelShaderImagePath", implementation::MediaResource::Empty()) \
|
||||
X(ConvergedAlignment, BackgroundImageAlignment, "backgroundImageAlignment", ConvergedAlignment::Horizontal_Center | ConvergedAlignment::Vertical_Center) \
|
||||
X(IMediaResource, BackgroundImagePath, "backgroundImage", implementation::MediaResource::Empty()) \
|
||||
X(Model::IntenseStyle, IntenseTextStyle, "intenseTextStyle", Model::IntenseStyle::Bright) \
|
||||
X(Core::AdjustTextMode, AdjustIndistinguishableColors, "adjustIndistinguishableColors", Core::AdjustTextMode::Automatic) \
|
||||
X(bool, UseAcrylic, "useAcrylic", false)
|
||||
@@ -169,163 +173,3 @@ Author(s):
|
||||
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedBackground, "unfocusedBackground", nullptr) \
|
||||
X(winrt::Microsoft::Terminal::Settings::Model::IconStyle, IconStyle, "iconStyle", winrt::Microsoft::Terminal::Settings::Model::IconStyle::Default) \
|
||||
X(winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility, ShowCloseButton, "showCloseButton", winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVisibility::Always)
|
||||
|
||||
// SettingKey enums: provide a generic way to reference settings by key.
|
||||
// Generated from the MTSM macros above. Also includes special-cased settings
|
||||
// that are not part of the macro lists (prefixed with _ to avoid name collisions).
|
||||
// SETTINGS_SIZE is a sentinel value that must remain last in each enum.
|
||||
namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
#define _MTSM_ENUM_VALUE(type, name, jsonKey, ...) name,
|
||||
|
||||
enum class ProfileSettingKey : int
|
||||
{
|
||||
MTSM_PROFILE_SETTINGS(_MTSM_ENUM_VALUE)
|
||||
// Special-cased profile settings (not in MTSM_PROFILE_SETTINGS due to
|
||||
// custom JSON parsing, but included here for completeness)
|
||||
_Name,
|
||||
_Guid,
|
||||
_Source,
|
||||
_Hidden,
|
||||
_Padding,
|
||||
_TabColor,
|
||||
// Complex/mutable settings with backing fields
|
||||
_Icon,
|
||||
_BellSound,
|
||||
SETTINGS_SIZE
|
||||
};
|
||||
|
||||
enum class GlobalSettingKey : int
|
||||
{
|
||||
MTSM_GLOBAL_SETTINGS(_MTSM_ENUM_VALUE)
|
||||
// Special-cased global settings
|
||||
_UnparsedDefaultProfile,
|
||||
// Complex/mutable settings with backing fields
|
||||
_NewTabMenu,
|
||||
SETTINGS_SIZE
|
||||
};
|
||||
|
||||
enum class FontSettingKey : int
|
||||
{
|
||||
MTSM_FONT_SETTINGS(_MTSM_ENUM_VALUE)
|
||||
SETTINGS_SIZE
|
||||
};
|
||||
|
||||
enum class AppearanceSettingKey : int
|
||||
{
|
||||
MTSM_APPEARANCE_SETTINGS(_MTSM_ENUM_VALUE)
|
||||
// Special-cased appearance settings
|
||||
_Foreground,
|
||||
_Background,
|
||||
_SelectionBackground,
|
||||
_CursorColor,
|
||||
_Opacity,
|
||||
_DarkColorSchemeName,
|
||||
_LightColorSchemeName,
|
||||
// Complex/mutable settings with backing fields
|
||||
_PixelShaderPath,
|
||||
_PixelShaderImagePath,
|
||||
_BackgroundImagePath,
|
||||
SETTINGS_SIZE
|
||||
};
|
||||
|
||||
#undef _MTSM_ENUM_VALUE
|
||||
|
||||
// JSON key lookup: returns the JSON key string for a given SettingKey.
|
||||
// Generated from the same macros to maintain a single source of truth.
|
||||
constexpr std::string_view JsonKeyForSetting(ProfileSettingKey key)
|
||||
{
|
||||
#define _MTSM_KEY_CASE(type, name, jsonKey, ...) \
|
||||
case ProfileSettingKey::name: \
|
||||
return jsonKey;
|
||||
switch (key)
|
||||
{
|
||||
MTSM_PROFILE_SETTINGS(_MTSM_KEY_CASE)
|
||||
case ProfileSettingKey::_Name:
|
||||
return "name";
|
||||
case ProfileSettingKey::_Guid:
|
||||
return "guid";
|
||||
case ProfileSettingKey::_Source:
|
||||
return "source";
|
||||
case ProfileSettingKey::_Hidden:
|
||||
return "hidden";
|
||||
case ProfileSettingKey::_Padding:
|
||||
return "padding";
|
||||
case ProfileSettingKey::_TabColor:
|
||||
return "tabColor";
|
||||
case ProfileSettingKey::_Icon:
|
||||
return "icon";
|
||||
case ProfileSettingKey::_BellSound:
|
||||
return "bellSound";
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
#undef _MTSM_KEY_CASE
|
||||
}
|
||||
|
||||
constexpr std::string_view JsonKeyForSetting(GlobalSettingKey key)
|
||||
{
|
||||
#define _MTSM_KEY_CASE(type, name, jsonKey, ...) \
|
||||
case GlobalSettingKey::name: \
|
||||
return jsonKey;
|
||||
switch (key)
|
||||
{
|
||||
MTSM_GLOBAL_SETTINGS(_MTSM_KEY_CASE)
|
||||
case GlobalSettingKey::_UnparsedDefaultProfile:
|
||||
return "defaultProfile";
|
||||
case GlobalSettingKey::_NewTabMenu:
|
||||
return "newTabMenu";
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
#undef _MTSM_KEY_CASE
|
||||
}
|
||||
|
||||
constexpr std::string_view JsonKeyForSetting(FontSettingKey key)
|
||||
{
|
||||
#define _MTSM_KEY_CASE(type, name, jsonKey, ...) \
|
||||
case FontSettingKey::name: \
|
||||
return jsonKey;
|
||||
switch (key)
|
||||
{
|
||||
MTSM_FONT_SETTINGS(_MTSM_KEY_CASE)
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
#undef _MTSM_KEY_CASE
|
||||
}
|
||||
|
||||
constexpr std::string_view JsonKeyForSetting(AppearanceSettingKey key)
|
||||
{
|
||||
#define _MTSM_KEY_CASE(type, name, jsonKey, ...) \
|
||||
case AppearanceSettingKey::name: \
|
||||
return jsonKey;
|
||||
switch (key)
|
||||
{
|
||||
MTSM_APPEARANCE_SETTINGS(_MTSM_KEY_CASE)
|
||||
case AppearanceSettingKey::_Foreground:
|
||||
return "foreground";
|
||||
case AppearanceSettingKey::_Background:
|
||||
return "background";
|
||||
case AppearanceSettingKey::_SelectionBackground:
|
||||
return "selectionBackground";
|
||||
case AppearanceSettingKey::_CursorColor:
|
||||
return "cursorColor";
|
||||
case AppearanceSettingKey::_Opacity:
|
||||
return "opacity";
|
||||
case AppearanceSettingKey::_DarkColorSchemeName:
|
||||
return "colorScheme";
|
||||
case AppearanceSettingKey::_LightColorSchemeName:
|
||||
return "colorScheme";
|
||||
case AppearanceSettingKey::_PixelShaderPath:
|
||||
return "experimental.pixelShaderPath";
|
||||
case AppearanceSettingKey::_PixelShaderImagePath:
|
||||
return "experimental.pixelShaderImagePath";
|
||||
case AppearanceSettingKey::_BackgroundImagePath:
|
||||
return "backgroundImage";
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
#undef _MTSM_KEY_CASE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ static constexpr std::string_view LegacyAutoMarkPromptsKey{ "experimental.autoMa
|
||||
static constexpr std::string_view LegacyShowMarksKey{ "experimental.showMarksOnScrollbar" };
|
||||
static constexpr std::string_view LegacyRightClickContextMenuKey{ "experimental.rightClickContextMenu" };
|
||||
|
||||
Profile::Profile(guid guid)
|
||||
Profile::Profile(guid guid) noexcept :
|
||||
_Guid(guid)
|
||||
{
|
||||
Guid(guid);
|
||||
}
|
||||
|
||||
void Profile::CreateUnfocusedAppearance()
|
||||
@@ -105,23 +105,25 @@ winrt::com_ptr<Profile> Profile::CopySettings() const
|
||||
profile->_Deleted = _Deleted;
|
||||
profile->_Orphaned = _Orphaned;
|
||||
profile->_Updates = _Updates;
|
||||
profile->_Guid = _Guid;
|
||||
profile->_Name = _Name;
|
||||
profile->_Source = _Source;
|
||||
profile->_Hidden = _Hidden;
|
||||
profile->_TabColor = _TabColor;
|
||||
profile->_Padding = _Padding;
|
||||
|
||||
profile->_Origin = _Origin;
|
||||
profile->_FontInfo = *fontInfo;
|
||||
profile->_DefaultAppearance = *defaultAppearance;
|
||||
profile->_json = _json;
|
||||
|
||||
// JSON-backed settings (Name, Source, Hidden, Guid, Padding, TabColor, MTSM settings)
|
||||
// all live in _json, which is already deep-copied above. No per-setting copy needed.
|
||||
#define PROFILE_SETTINGS_COPY(type, name, jsonKey, ...) \
|
||||
profile->_##name = _##name;
|
||||
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_COPY)
|
||||
#undef PROFILE_SETTINGS_COPY
|
||||
|
||||
// Complex/mutable settings — backing fields for resolution lifecycle.
|
||||
// _json (copied above) is the source of truth; backing fields hold resolved runtime state.
|
||||
profile->_Icon = _Icon;
|
||||
|
||||
|
||||
// BellSound is an IVector<>, so we need to make a new vector pointing at the same objects
|
||||
if (_BellSound)
|
||||
{
|
||||
// BellSound is an IVector<>, so we need to make a new vector pointing at the same objects
|
||||
profile->_BellSound = winrt::single_threaded_vector(wil::to_vector(*_BellSound));
|
||||
}
|
||||
|
||||
@@ -167,10 +169,6 @@ winrt::com_ptr<winrt::Microsoft::Terminal::Settings::Model::implementation::Prof
|
||||
// <none>
|
||||
void Profile::LayerJson(const Json::Value& json)
|
||||
{
|
||||
// Merge incoming JSON keys into stored _json (key-wise, not replacement).
|
||||
// This preserves keys from earlier LayerJson calls that aren't in the new JSON.
|
||||
JsonUtils::MergeJsonKeys(json, _json);
|
||||
|
||||
// Appearance Settings
|
||||
auto defaultAppearanceImpl = winrt::get_self<implementation::AppearanceConfig>(_DefaultAppearance);
|
||||
defaultAppearanceImpl->LayerJson(json);
|
||||
@@ -179,53 +177,37 @@ void Profile::LayerJson(const Json::Value& json)
|
||||
auto fontInfoImpl = winrt::get_self<implementation::FontConfig>(_FontInfo);
|
||||
fontInfoImpl->LayerJson(json);
|
||||
|
||||
// Profile-specific settings: now JSON-backed. Values are already in _json
|
||||
// from the merge step above. Only need to handle non-JSON fields and logging.
|
||||
// Profile-specific Settings
|
||||
JsonUtils::GetValueForKey(json, NameKey, _Name);
|
||||
JsonUtils::GetValueForKey(json, UpdatesKey, _Updates);
|
||||
|
||||
// Normalize Padding: allow integer → string coercion (e.g. "padding": 8 → "8")
|
||||
if (_json.isMember(JsonKey(PaddingKey)) && _json[JsonKey(PaddingKey)].isInt())
|
||||
{
|
||||
_json[JsonKey(PaddingKey)] = std::to_string(_json[JsonKey(PaddingKey)].asInt());
|
||||
}
|
||||
JsonUtils::GetValueForKey(json, GuidKey, _Guid);
|
||||
|
||||
// Make sure Source is before Hidden! We use that to exclude false positives from the settings logger!
|
||||
_logSettingIfSet(HiddenKey, HasHidden());
|
||||
_logSettingIfSet(PaddingKey, HasPadding());
|
||||
_logSettingIfSet(TabColorKey, HasTabColor());
|
||||
JsonUtils::GetValueForKey(json, SourceKey, _Source);
|
||||
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
|
||||
_logSettingIfSet(HiddenKey, _Hidden.has_value());
|
||||
|
||||
// Padding was never specified as an integer, but it was a common working mistake.
|
||||
// Allow it to be permissive.
|
||||
JsonUtils::GetValueForKey(json, PaddingKey, _Padding, JsonUtils::OptionalConverter<hstring, JsonUtils::PermissiveStringConverter<std::wstring>>{});
|
||||
_logSettingIfSet(PaddingKey, _Padding.has_value());
|
||||
|
||||
JsonUtils::GetValueForKey(json, TabColorKey, _TabColor);
|
||||
_logSettingIfSet(TabColorKey, _TabColor.has_value());
|
||||
|
||||
// Try to load some legacy keys, to migrate them.
|
||||
// Normalize legacy keys into canonical _json keys so JSON-backed getters find them.
|
||||
// Done _before_ the MTSM_PROFILE_SETTINGS logging, which have the updated keys.
|
||||
static constexpr std::pair<std::string_view, std::string_view> legacyKeyMappings[] = {
|
||||
{ LegacyShowMarksKey, "showMarksOnScrollbar" },
|
||||
{ LegacyAutoMarkPromptsKey, "autoMarkPrompts" },
|
||||
{ LegacyRightClickContextMenuKey, "rightClickContextMenu" },
|
||||
};
|
||||
for (const auto& [legacyKey, canonicalKey] : legacyKeyMappings)
|
||||
{
|
||||
if (json.isMember(JsonKey(legacyKey)))
|
||||
{
|
||||
_json[JsonKey(canonicalKey)] = json[JsonKey(legacyKey)];
|
||||
}
|
||||
}
|
||||
// Done _before_ the MTSM_PROFILE_SETTINGS, which have the updated keys.
|
||||
JsonUtils::GetValueForKey(json, LegacyShowMarksKey, _ShowMarks);
|
||||
JsonUtils::GetValueForKey(json, LegacyAutoMarkPromptsKey, _AutoMarkPrompts);
|
||||
JsonUtils::GetValueForKey(json, LegacyRightClickContextMenuKey, _RightClickContextMenu);
|
||||
|
||||
// MTSM settings are now JSON-backed (no backing fields).
|
||||
// Values are already in _json from the merge step above.
|
||||
// We only need to log which settings were set in this layer.
|
||||
#define PROFILE_SETTINGS_LAYER_JSON(type, name, jsonKey, ...) \
|
||||
_logSettingIfSet(jsonKey, json.isMember(jsonKey) && !json[jsonKey].isNull());
|
||||
JsonUtils::GetValueForKey(json, jsonKey, _##name); \
|
||||
_logSettingIfSet(jsonKey, _##name.has_value());
|
||||
|
||||
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_LAYER_JSON)
|
||||
#undef PROFILE_SETTINGS_LAYER_JSON
|
||||
|
||||
// Complex/mutable settings — backing fields populated from _json for runtime resolution.
|
||||
// _json is the source of truth for serialization; backing fields are for resolution lifecycle.
|
||||
JsonUtils::GetValueForKey(json, "icon", _Icon);
|
||||
_logSettingIfSet("icon", _Icon.has_value());
|
||||
JsonUtils::GetValueForKey(json, "bellSound", _BellSound);
|
||||
_logSettingIfSet("bellSound", _BellSound.has_value());
|
||||
|
||||
if (json.isMember(JsonKey(UnfocusedAppearanceKey)))
|
||||
{
|
||||
auto unfocusedAppearance{ winrt::make_self<implementation::AppearanceConfig>(weak_ref<Model::Profile>(*this)) };
|
||||
@@ -350,44 +332,25 @@ Json::Value Profile::ToJson() const
|
||||
// GH #9962:
|
||||
// If the settings.json was missing, when we load the dynamic profiles, they are completely empty.
|
||||
// This caused us to serialize empty profiles "{}" on accident.
|
||||
const auto writeBasicSettings{ HasSource() };
|
||||
const auto writeBasicSettings{ !Source().empty() };
|
||||
|
||||
// Profile-specific Settings (JSON-backed)
|
||||
if (writeBasicSettings)
|
||||
{
|
||||
// Dynamic profiles: write resolved values so defaults are materialized
|
||||
JsonUtils::SetValueForKey(json, NameKey, Name());
|
||||
JsonUtils::SetValueForKey(json, GuidKey, Guid());
|
||||
JsonUtils::SetValueForKey(json, HiddenKey, Hidden());
|
||||
JsonUtils::SetValueForKey(json, SourceKey, Source());
|
||||
}
|
||||
else
|
||||
{
|
||||
// User-defined profiles: copy local layer from _json
|
||||
for (const auto& key : { NameKey, GuidKey, HiddenKey, SourceKey })
|
||||
{
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, key);
|
||||
}
|
||||
}
|
||||
// Profile-specific Settings
|
||||
JsonUtils::SetValueForKey(json, NameKey, writeBasicSettings ? Name() : _Name);
|
||||
JsonUtils::SetValueForKey(json, GuidKey, writeBasicSettings ? Guid() : _Guid);
|
||||
JsonUtils::SetValueForKey(json, HiddenKey, writeBasicSettings ? Hidden() : _Hidden);
|
||||
JsonUtils::SetValueForKey(json, SourceKey, writeBasicSettings ? Source() : _Source);
|
||||
|
||||
// Padding: copy from _json
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, PaddingKey);
|
||||
// PermissiveStringConverter is unnecessary for serialization
|
||||
JsonUtils::SetValueForKey(json, PaddingKey, _Padding);
|
||||
|
||||
// TabColor: nullable — key presence matters (explicit null is valid)
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, TabColorKey);
|
||||
JsonUtils::SetValueForKey(json, TabColorKey, _TabColor);
|
||||
|
||||
// MTSM profile settings: copy from _json (the source of truth)
|
||||
#define PROFILE_SETTINGS_TO_JSON(type, name, jsonKey, ...) \
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, jsonKey);
|
||||
JsonUtils::SetValueForKey(json, jsonKey, _##name);
|
||||
|
||||
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_TO_JSON)
|
||||
#undef PROFILE_SETTINGS_TO_JSON
|
||||
|
||||
// Complex/mutable settings with backing fields (runtime resolution)
|
||||
// Read from _json (source of truth), not from backing fields
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, "icon");
|
||||
JsonUtils::CopyKeyIfPresent(_json, json, "bellSound");
|
||||
|
||||
if (auto fontJSON = winrt::get_self<FontConfig>(_FontInfo)->ToJson(); !fontJSON.empty())
|
||||
{
|
||||
json[JsonKey(FontInfoKey)] = std::move(fontJSON);
|
||||
@@ -401,89 +364,6 @@ Json::Value Profile::ToJson() const
|
||||
return json;
|
||||
}
|
||||
|
||||
bool Profile::HasSetting(ProfileSettingKey key) const
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
#define _PROFILE_HAS_SETTING(type, name, jsonKey, ...) \
|
||||
case ProfileSettingKey::name: \
|
||||
return Has##name();
|
||||
MTSM_PROFILE_SETTINGS(_PROFILE_HAS_SETTING)
|
||||
#undef _PROFILE_HAS_SETTING
|
||||
case ProfileSettingKey::_Name:
|
||||
return HasName();
|
||||
case ProfileSettingKey::_Guid:
|
||||
return HasGuid();
|
||||
case ProfileSettingKey::_Source:
|
||||
return HasSource();
|
||||
case ProfileSettingKey::_Hidden:
|
||||
return HasHidden();
|
||||
case ProfileSettingKey::_Padding:
|
||||
return HasPadding();
|
||||
case ProfileSettingKey::_TabColor:
|
||||
return HasTabColor();
|
||||
case ProfileSettingKey::_Icon:
|
||||
return HasIcon();
|
||||
case ProfileSettingKey::_BellSound:
|
||||
return HasBellSound();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Profile::ClearSetting(ProfileSettingKey key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
#define _PROFILE_CLEAR_SETTING(type, name, jsonKey, ...) \
|
||||
case ProfileSettingKey::name: \
|
||||
Clear##name(); \
|
||||
break;
|
||||
MTSM_PROFILE_SETTINGS(_PROFILE_CLEAR_SETTING)
|
||||
#undef _PROFILE_CLEAR_SETTING
|
||||
case ProfileSettingKey::_Name:
|
||||
ClearName();
|
||||
break;
|
||||
case ProfileSettingKey::_Guid:
|
||||
ClearGuid();
|
||||
break;
|
||||
case ProfileSettingKey::_Source:
|
||||
ClearSource();
|
||||
break;
|
||||
case ProfileSettingKey::_Hidden:
|
||||
ClearHidden();
|
||||
break;
|
||||
case ProfileSettingKey::_Padding:
|
||||
ClearPadding();
|
||||
break;
|
||||
case ProfileSettingKey::_TabColor:
|
||||
ClearTabColor();
|
||||
break;
|
||||
case ProfileSettingKey::_Icon:
|
||||
ClearIcon();
|
||||
break;
|
||||
case ProfileSettingKey::_BellSound:
|
||||
ClearBellSound();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ProfileSettingKey> Profile::CurrentSettings() const
|
||||
{
|
||||
std::vector<ProfileSettingKey> result;
|
||||
for (auto i = 0; i < static_cast<int>(ProfileSettingKey::SETTINGS_SIZE); i++)
|
||||
{
|
||||
const auto key = static_cast<ProfileSettingKey>(i);
|
||||
if (HasSetting(key))
|
||||
{
|
||||
result.push_back(key);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Given a commandLine like the following:
|
||||
// * "C:\WINDOWS\System32\cmd.exe"
|
||||
// * "pwsh -WorkingDirectory ~"
|
||||
@@ -622,13 +502,13 @@ void Profile::_logSettingIfSet(const std::string_view& setting, const bool isSet
|
||||
|
||||
// Exclude some false positives from userDefaults.json
|
||||
// NOTE: we can't use the OriginTag here because it hasn't been set yet!
|
||||
const bool isWinPow = HasGuid() && Guid() == DEFAULT_WINDOWS_POWERSHELL_GUID;
|
||||
const bool isCmd = HasGuid() && Guid() == DEFAULT_COMMAND_PROMPT_GUID;
|
||||
const bool isACS = HasName() && til::equals_insensitive_ascii(Name(), L"Azure Cloud Shell");
|
||||
const bool isWTDynamicProfile = HasSource() && til::starts_with(Source(), L"Windows.Terminal");
|
||||
const bool settingHiddenToFalse = til::equals_insensitive_ascii(setting, HiddenKey) && HasHidden() && Hidden() == false;
|
||||
const bool settingCommandlineToWinPow = til::equals_insensitive_ascii(setting, "commandline") && HasCommandline() && til::equals_insensitive_ascii(Commandline(), L"%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe");
|
||||
const bool settingCommandlineToCmd = til::equals_insensitive_ascii(setting, "commandline") && HasCommandline() && til::equals_insensitive_ascii(Commandline(), L"%SystemRoot%\\System32\\cmd.exe");
|
||||
const bool isWinPow = _Guid.has_value() && *_Guid == DEFAULT_WINDOWS_POWERSHELL_GUID; //_Name.has_value() && til::equals_insensitive_ascii(*_Name, L"Windows PowerShell");
|
||||
const bool isCmd = _Guid.has_value() && *_Guid == DEFAULT_COMMAND_PROMPT_GUID; //_Name.has_value() && til::equals_insensitive_ascii(*_Name, L"Command Prompt");
|
||||
const bool isACS = _Name.has_value() && til::equals_insensitive_ascii(*_Name, L"Azure Cloud Shell");
|
||||
const bool isWTDynamicProfile = _Source.has_value() && til::starts_with(*_Source, L"Windows.Terminal");
|
||||
const bool settingHiddenToFalse = til::equals_insensitive_ascii(setting, HiddenKey) && _Hidden.has_value() && _Hidden == false;
|
||||
const bool settingCommandlineToWinPow = til::equals_insensitive_ascii(setting, "commandline") && _Commandline.has_value() && til::equals_insensitive_ascii(*_Commandline, L"%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe");
|
||||
const bool settingCommandlineToCmd = til::equals_insensitive_ascii(setting, "commandline") && _Commandline.has_value() && til::equals_insensitive_ascii(*_Commandline, L"%SystemRoot%\\System32\\cmd.exe");
|
||||
// clang-format off
|
||||
if (!(isWinPow && (settingHiddenToFalse || settingCommandlineToWinPow))
|
||||
&& !(isCmd && (settingHiddenToFalse || settingCommandlineToCmd))
|
||||
@@ -661,7 +541,7 @@ void Profile::ResolveMediaResources(const Model::MediaResourceResolver& resolver
|
||||
auto newIcon{ MediaResource::FromString(icon->Path()) };
|
||||
const std::wstring cmdline{ NormalizeCommandLine(iconSource->Commandline().c_str()) };
|
||||
newIcon.Resolve(cmdline.c_str() /* c_str: give hstring a chance to find the null terminator */);
|
||||
iconSource->Icon(std::move(newIcon));
|
||||
iconSource->_Icon = std::move(newIcon);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ Author(s):
|
||||
#include "MTSMSettings.h"
|
||||
|
||||
#include "JsonUtils.h"
|
||||
#include "TerminalSettingsSerializationHelpers.h"
|
||||
#include <DefaultSettings.h>
|
||||
#include "MediaResourceSupport.h"
|
||||
#include "AppearanceConfig.h"
|
||||
@@ -81,10 +80,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
public:
|
||||
Profile() noexcept = default;
|
||||
// Not noexcept: Guid(guid) writes to _json, which allocates.
|
||||
// The old backing-field constructor was noexcept (POD copy into std::optional),
|
||||
// but JSON-backed storage requires heap allocation.
|
||||
Profile(guid guid);
|
||||
Profile(guid guid) noexcept;
|
||||
|
||||
void CreateUnfocusedAppearance();
|
||||
void DeleteUnfocusedAppearance();
|
||||
@@ -102,11 +98,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
void LayerJson(const Json::Value& json);
|
||||
Json::Value ToJson() const;
|
||||
|
||||
// Generic setting access via SettingKey
|
||||
bool HasSetting(ProfileSettingKey key) const;
|
||||
void ClearSetting(ProfileSettingKey key);
|
||||
std::vector<ProfileSettingKey> CurrentSettings() const;
|
||||
|
||||
hstring EvaluatedStartingDirectory() const;
|
||||
|
||||
Model::IAppearanceConfig DefaultAppearance();
|
||||
@@ -131,29 +122,16 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
WINRT_PROPERTY(OriginTag, Origin, OriginTag::None);
|
||||
WINRT_PROPERTY(guid, Updates);
|
||||
|
||||
// Nullable/optional settings (JSON-backed)
|
||||
INHERITABLE_NULLABLE_SETTING(Model::Profile, Microsoft::Terminal::Core::Color, TabColor, "tabColor", nullptr)
|
||||
INHERITABLE_MUTABLE_SETTING(Model::Profile, Model::IAppearanceConfig, UnfocusedAppearance, nullptr);
|
||||
// Nullable/optional settings
|
||||
INHERITABLE_NULLABLE_SETTING(Model::Profile, Microsoft::Terminal::Core::Color, TabColor, nullptr);
|
||||
INHERITABLE_SETTING(Model::Profile, Model::IAppearanceConfig, UnfocusedAppearance, nullptr);
|
||||
|
||||
// Settings that are JSON-backed but need custom handling in ToJson/LayerJson
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, Name, "name", L"Default")
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, Source, "source")
|
||||
INHERITABLE_SETTING(Model::Profile, bool, Hidden, "hidden", false)
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, Padding, "padding", DEFAULT_PADDING)
|
||||
|
||||
// Guid: hand-written JSON-backed (dynamic default)
|
||||
_BASE_INHERITABLE_SETTING(Model::Profile, guid, Guid, "guid")
|
||||
public:
|
||||
guid Guid() const
|
||||
{
|
||||
const auto val{ _getGuidImpl() };
|
||||
return val ? *val : _GenerateGuidForProfile(Name(), Source());
|
||||
}
|
||||
void Guid(const guid& value)
|
||||
{
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::SetValueForKey(
|
||||
_json, "guid", value);
|
||||
}
|
||||
// Settings that cannot be put in the macro because of how they are handled in ToJson/LayerJson
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default");
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, Source);
|
||||
INHERITABLE_SETTING(Model::Profile, bool, Hidden, false);
|
||||
INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
|
||||
INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING);
|
||||
|
||||
winrt::hstring SourceBasePath;
|
||||
|
||||
@@ -163,33 +141,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_INITIALIZE)
|
||||
#undef PROFILE_SETTINGS_INITIALIZE
|
||||
|
||||
// IMediaResource settings with backing fields for resolution lifecycle.
|
||||
// _json is the source of truth for serialization. Setters dual-write to both
|
||||
// the backing field (for runtime resolution) and _json (for auto-save).
|
||||
INHERITABLE_MEDIA_RESOURCE_SETTING(Model::Profile, Icon, "icon", implementation::MediaResource::FromString(L"\uE756"))
|
||||
|
||||
// BellSound: IVector<IMediaResource> with backing field + dual-write setter.
|
||||
_BASE_INHERITABLE_MUTABLE_SETTING(Model::Profile, std::optional<Windows::Foundation::Collections::IVector<IMediaResource>>, BellSound, nullptr)
|
||||
public:
|
||||
Windows::Foundation::Collections::IVector<IMediaResource> BellSound() const
|
||||
{
|
||||
const auto val{ _getBellSoundImpl() };
|
||||
return val ? *val : nullptr;
|
||||
}
|
||||
void BellSound(const Windows::Foundation::Collections::IVector<IMediaResource>& value)
|
||||
{
|
||||
_BellSound = value;
|
||||
::Microsoft::Terminal::Settings::Model::JsonUtils::SetValueForKey(_json, "bellSound", value);
|
||||
}
|
||||
|
||||
private:
|
||||
Model::IAppearanceConfig _DefaultAppearance{ winrt::make<AppearanceConfig>(weak_ref<Model::Profile>(*this)) };
|
||||
Model::FontConfig _FontInfo{ winrt::make<FontConfig>(weak_ref<Model::Profile>(*this)) };
|
||||
|
||||
// Raw JSON for this layer. Populated by LayerJson(), will become the
|
||||
// source of truth for settings once the JSON-backed refactor is complete.
|
||||
Json::Value _json{ Json::ValueType::objectValue };
|
||||
|
||||
std::set<std::string> _changeLog;
|
||||
|
||||
static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
|
||||
|
||||
@@ -94,6 +94,5 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
|
||||
|
||||
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.PathTranslationStyle, PathTranslationStyle);
|
||||
INHERITABLE_PROFILE_SETTING(String, DragDropDelimiter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,13 +313,10 @@ namespace ControlUnitTests
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point terminalPosition0{ 0, 0 };
|
||||
const auto cursorPosition0 = terminalPosition0 * fontSize;
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -332,28 +329,29 @@ namespace ControlUnitTests
|
||||
// move not quite a whole cell, but enough to start a selection
|
||||
const til::point terminalPosition1{ 0, 0 };
|
||||
const til::point cursorPosition1{ 6, 0 };
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
Log::Comment(L"Drag the mouse down a whole row");
|
||||
const til::point terminalPosition2{ 1, 1 };
|
||||
const auto cursorPosition2 = terminalPosition2 * fontSize;
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition2.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition2.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's now two selections (one on each row)");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
Log::Comment(L"Release the mouse");
|
||||
interactivity->PointerReleased(0,
|
||||
noMouseDown,
|
||||
interactivity->PointerReleased(noMouseDown,
|
||||
WM_LBUTTONUP, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition2.to_core_point());
|
||||
@@ -363,8 +361,7 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"click outside the current selection");
|
||||
const til::point terminalPosition3{ 2, 2 };
|
||||
const auto cursorPosition3 = terminalPosition3 * fontSize;
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -375,11 +372,12 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Drag the mouse");
|
||||
const til::point terminalPosition4{ 3, 2 };
|
||||
const auto cursorPosition4 = terminalPosition4 * fontSize;
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition4.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition4.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's now one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
}
|
||||
@@ -410,17 +408,10 @@ namespace ControlUnitTests
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
|
||||
interactivity->GotFocus();
|
||||
// This test is sensitive to the number of rows scrolled per scroll wheel,
|
||||
// which is reloaded from the system parameters when focus is received.
|
||||
// Reset it.
|
||||
interactivity->_rowsToScroll = 1;
|
||||
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point terminalPosition0{ 5, 5 };
|
||||
const auto cursorPosition0{ terminalPosition0 * fontSize };
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -435,11 +426,12 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Drag the mouse just a little");
|
||||
// move not quite a whole cell, but enough to start a selection
|
||||
const auto cursorPosition1{ cursorPosition0 + til::point{ 6, 0 } };
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@@ -567,12 +559,9 @@ namespace ControlUnitTests
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point cursorPosition0{ 6, 0 };
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -586,11 +575,12 @@ namespace ControlUnitTests
|
||||
|
||||
Log::Comment(L"Drag the mouse a lot. This simulates dragging the mouse real fast.");
|
||||
const til::point cursorPosition1{ 6 + fontSize.width * 2, 0 };
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@@ -612,13 +602,10 @@ namespace ControlUnitTests
|
||||
const auto leftMouseDown{ Control::MouseButtonState::IsLeftButtonDown };
|
||||
const Control::MouseButtonState noMouseDown{};
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point cursorPosition0{ 6, 0 };
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -632,11 +619,12 @@ namespace ControlUnitTests
|
||||
|
||||
Log::Comment(L"Drag the mouse a lot. This simulates dragging the mouse real fast.");
|
||||
const til::point cursorPosition1{ 6 + fontSize.width * 2, 0 };
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@@ -646,8 +634,7 @@ namespace ControlUnitTests
|
||||
til::point expectedEnd{ 3, 0 }; // add 1 to x-coordinate because end is exclusive
|
||||
VERIFY_ARE_EQUAL(expectedEnd, core->_terminal->GetSelectionEnd());
|
||||
|
||||
interactivity->PointerReleased(0,
|
||||
noMouseDown,
|
||||
interactivity->PointerReleased(noMouseDown,
|
||||
WM_LBUTTONUP,
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
@@ -657,11 +644,12 @@ namespace ControlUnitTests
|
||||
|
||||
Log::Comment(L"Simulate dragging the mouse into the control, without first clicking into the control");
|
||||
const til::point cursorPosition2{ fontSize.width * 10, 0 };
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition2.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition2.to_core_point(),
|
||||
false);
|
||||
|
||||
Log::Comment(L"The selection should be unchanged.");
|
||||
VERIFY_ARE_EQUAL(expectedAnchor, core->_terminal->GetSelectionAnchor());
|
||||
@@ -688,12 +676,6 @@ namespace ControlUnitTests
|
||||
auto expectedViewHeight = 20;
|
||||
auto expectedBufferHeight = 20;
|
||||
|
||||
interactivity->GotFocus();
|
||||
// This test is sensitive to the number of rows scrolled per scroll wheel,
|
||||
// which is reloaded from the system parameters when focus is received.
|
||||
// Reset it.
|
||||
interactivity->_rowsToScroll = 1;
|
||||
|
||||
auto scrollChangedHandler = [&](auto&&, const Control::ScrollPositionChangedArgs& args) mutable {
|
||||
VERIFY_ARE_EQUAL(expectedTop, args.ViewTop());
|
||||
VERIFY_ARE_EQUAL(expectedViewHeight, args.ViewHeight());
|
||||
@@ -740,8 +722,7 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point terminalPosition0{ 4, 4 };
|
||||
const auto cursorPosition0 = terminalPosition0 * fontSize;
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -754,11 +735,12 @@ namespace ControlUnitTests
|
||||
// move the mouse as if to make a selection
|
||||
const til::point terminalPosition1{ 10, 4 };
|
||||
const auto cursorPosition1 = terminalPosition1 * fontSize;
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's still no selection");
|
||||
VERIFY_IS_FALSE(core->HasSelection());
|
||||
}
|
||||
@@ -788,13 +770,10 @@ namespace ControlUnitTests
|
||||
|
||||
const til::size fontSize{ 9, 21 };
|
||||
|
||||
interactivity->GotFocus();
|
||||
|
||||
Log::Comment(L"Click on the terminal");
|
||||
const til::point terminalPosition0{ 5, 5 };
|
||||
const auto cursorPosition0{ terminalPosition0 * fontSize };
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -809,11 +788,12 @@ namespace ControlUnitTests
|
||||
Log::Comment(L"Drag the mouse just a little");
|
||||
// move not quite a whole cell, but enough to start a selection
|
||||
const auto cursorPosition1{ cursorPosition0 + til::point{ 6, 0 } };
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
Log::Comment(L"Verify that there's one selection");
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
|
||||
@@ -870,11 +850,12 @@ namespace ControlUnitTests
|
||||
// character in the buffer (if, albeit in a new location).
|
||||
//
|
||||
// This helps test GH #14462, a regression from #10749.
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition0.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition0.to_core_point(),
|
||||
true);
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
{
|
||||
const auto anchor{ core->_terminal->GetSelectionAnchor() };
|
||||
@@ -895,11 +876,12 @@ namespace ControlUnitTests
|
||||
expectedAnchor.y -= 1;
|
||||
expectedEnd.y -= 1;
|
||||
VERIFY_ARE_EQUAL(scrollbackLength - 3, core->_terminal->GetScrollOffset());
|
||||
interactivity->PointerMoved(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerMoved(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
modifiers,
|
||||
cursorPosition1.to_core_point());
|
||||
true, // focused,
|
||||
cursorPosition1.to_core_point(),
|
||||
true);
|
||||
VERIFY_IS_TRUE(core->HasSelection());
|
||||
{
|
||||
const auto anchor{ core->_terminal->GetSelectionAnchor() };
|
||||
@@ -947,8 +929,7 @@ namespace ControlUnitTests
|
||||
const til::size fontSize{ 9, 21 };
|
||||
const til::point terminalPosition0{ 5, 5 };
|
||||
const auto cursorPosition0{ terminalPosition0 * fontSize };
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -997,8 +978,7 @@ namespace ControlUnitTests
|
||||
const til::size fontSize{ 9, 21 };
|
||||
const til::point terminalPosition0{ 5, 5 };
|
||||
const auto cursorPosition0{ terminalPosition0 * fontSize };
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -1014,8 +994,7 @@ namespace ControlUnitTests
|
||||
// The viewport is only 30 wide, so clamping 35 to the buffer size gets
|
||||
// us 29, which converted is (32 + 29 + 1) = 62 = '>'
|
||||
expectedOutput.push_back(L"\x1b[M >&");
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -1030,8 +1009,7 @@ namespace ControlUnitTests
|
||||
// will be clamped to the top line.
|
||||
|
||||
expectedOutput.push_back(L"\x1b[M &!"); // 5, 1
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -1047,8 +1025,7 @@ namespace ControlUnitTests
|
||||
VERIFY_ARE_EQUAL(0, core->ScrollOffset());
|
||||
Log::Comment(L" --- Click on a spot that's still outside the buffer ---");
|
||||
expectedOutput.push_back(L"\x1b[M >&");
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
@@ -1062,8 +1039,7 @@ namespace ControlUnitTests
|
||||
Log::Comment(L" --- Click on a spot that's NOW INSIDE the buffer ---");
|
||||
// (32 + 35 + 1) = 68 = 'D'
|
||||
expectedOutput.push_back(L"\x1b[M D&");
|
||||
interactivity->PointerPressed(0,
|
||||
leftMouseDown,
|
||||
interactivity->PointerPressed(leftMouseDown,
|
||||
WM_LBUTTONDOWN, //pointerUpdateKind
|
||||
0, // timestamp
|
||||
modifiers,
|
||||
|
||||
@@ -105,10 +105,9 @@ namespace SettingsModelUnitTests
|
||||
TEST_METHOD(RealResolverUrlCases);
|
||||
TEST_METHOD(RealResolverUNCCases);
|
||||
|
||||
// These are normalized by NormalizeCommandLine, which resolves to the on-disk casing.
|
||||
// They are used in test cases where media paths fall back to profile command lines.
|
||||
static inline std::wstring overrideCommandline;
|
||||
static inline std::wstring cmdCommandline;
|
||||
static constexpr std::wstring_view pingCommandline{ LR"(C:\Windows\System32\PING.EXE)" }; // Normalized by Profile (this is the casing that Windows stores on disk)
|
||||
static constexpr std::wstring_view overrideCommandline{ LR"(C:\Windows\System32\cscript.exe)" };
|
||||
static constexpr std::wstring_view cmdCommandline{ LR"(C:\Windows\System32\cmd.exe)" }; // The default commandline for a profile
|
||||
static constexpr std::wstring_view fragmentBasePath1{ LR"(C:\Windows\Media)" };
|
||||
|
||||
private:
|
||||
@@ -219,9 +218,6 @@ namespace SettingsModelUnitTests
|
||||
// Some of our tests use paths under system32. Just don't redirect them.
|
||||
Wow64DisableWow64FsRedirection(&redirectionFlag);
|
||||
#endif
|
||||
// Normalize these AFTER the call above so that we get the correctly redirected paths.
|
||||
overrideCommandline = implementation::Profile::NormalizeCommandLine(LR"(C:\Windows\System32\cscript.exe)");
|
||||
cmdCommandline = implementation::Profile::NormalizeCommandLine(LR"(C:\Windows\System32\cmd.exe)");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,14 +31,6 @@ namespace SettingsModelUnitTests
|
||||
TEST_METHOD(TestGenGuidsForProfiles);
|
||||
TEST_METHOD(TestCorrectOldDefaultShellPaths);
|
||||
TEST_METHOD(ProfileDefaultsProhibitedSettings);
|
||||
|
||||
TEST_METHOD(JsonSyncOnSetAndClear);
|
||||
TEST_METHOD(SettingKeyEnumAndJsonKeyLookup);
|
||||
TEST_METHOD(GenericHasAndClearMatchTypedAPIs);
|
||||
TEST_METHOD(CurrentSettingsReturnsCorrectKeys);
|
||||
TEST_METHOD(SpecialCasedSettingsJsonBacked);
|
||||
TEST_METHOD(NullableSettingJsonBacked);
|
||||
TEST_METHOD(ColorSchemeJsonBacked);
|
||||
};
|
||||
|
||||
void ProfileTests::ProfileGeneratesGuid()
|
||||
@@ -540,424 +532,4 @@ namespace SettingsModelUnitTests
|
||||
VERIFY_ARE_NOT_EQUAL(L"Default Profile Source", allProfiles.GetAt(2).Source());
|
||||
VERIFY_ARE_NOT_EQUAL(L"foo.exe", allProfiles.GetAt(2).Commandline());
|
||||
}
|
||||
|
||||
void ProfileTests::JsonSyncOnSetAndClear()
|
||||
{
|
||||
// Verify that setting a value via the typed setter updates the internal
|
||||
// _json, and clearing it removes the key from _json.
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1000
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
|
||||
// Verify initial value
|
||||
VERIFY_ARE_EQUAL(1000, profile.HistorySize());
|
||||
VERIFY_IS_TRUE(profile.HasHistorySize());
|
||||
|
||||
// Modify setting; _json should be updated
|
||||
profile.HistorySize(5000);
|
||||
VERIFY_ARE_EQUAL(5000, profile.HistorySize());
|
||||
|
||||
// Verify ToJson reflects the change
|
||||
const auto json = profileImpl->ToJson();
|
||||
VERIFY_ARE_EQUAL(5000, json["historySize"].asInt());
|
||||
|
||||
// Clear setting; should fall back to default
|
||||
profile.ClearHistorySize();
|
||||
VERIFY_IS_FALSE(profile.HasHistorySize());
|
||||
// Should now inherit or use default (9001 is the DEFAULT_HISTORY_SIZE)
|
||||
VERIFY_ARE_EQUAL(DEFAULT_HISTORY_SIZE, profile.HistorySize());
|
||||
|
||||
// ToJson should no longer have historySize
|
||||
const auto json2 = profileImpl->ToJson();
|
||||
VERIFY_IS_FALSE(json2.isMember("historySize"));
|
||||
}
|
||||
|
||||
void ProfileTests::SettingKeyEnumAndJsonKeyLookup()
|
||||
{
|
||||
// Verify that the SettingKey enums map to correct JSON keys.
|
||||
using namespace implementation;
|
||||
|
||||
// Spot-check a few profile setting keys
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "historySize" }, JsonKeyForSetting(ProfileSettingKey::HistorySize));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "snapOnInput" }, JsonKeyForSetting(ProfileSettingKey::SnapOnInput));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "commandline" }, JsonKeyForSetting(ProfileSettingKey::Commandline));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "tabTitle" }, JsonKeyForSetting(ProfileSettingKey::TabTitle));
|
||||
|
||||
// Special-cased settings
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "name" }, JsonKeyForSetting(ProfileSettingKey::_Name));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "guid" }, JsonKeyForSetting(ProfileSettingKey::_Guid));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "hidden" }, JsonKeyForSetting(ProfileSettingKey::_Hidden));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "padding" }, JsonKeyForSetting(ProfileSettingKey::_Padding));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "tabColor" }, JsonKeyForSetting(ProfileSettingKey::_TabColor));
|
||||
|
||||
// Global setting keys
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "initialRows" }, JsonKeyForSetting(GlobalSettingKey::InitialRows));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "alwaysOnTop" }, JsonKeyForSetting(GlobalSettingKey::AlwaysOnTop));
|
||||
|
||||
// Font setting keys
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "face" }, JsonKeyForSetting(FontSettingKey::FontFace));
|
||||
VERIFY_ARE_EQUAL(std::string_view{ "size" }, JsonKeyForSetting(FontSettingKey::FontSize));
|
||||
|
||||
// SETTINGS_SIZE should be a valid (but large) enum value
|
||||
VERIFY_IS_TRUE(static_cast<int>(ProfileSettingKey::SETTINGS_SIZE) > 0);
|
||||
VERIFY_IS_TRUE(static_cast<int>(GlobalSettingKey::SETTINGS_SIZE) > 0);
|
||||
VERIFY_IS_TRUE(static_cast<int>(FontSettingKey::SETTINGS_SIZE) > 0);
|
||||
VERIFY_IS_TRUE(static_cast<int>(AppearanceSettingKey::SETTINGS_SIZE) > 0);
|
||||
}
|
||||
|
||||
void ProfileTests::GenericHasAndClearMatchTypedAPIs()
|
||||
{
|
||||
// Verify that HasSetting(key) and ClearSetting(key) match the
|
||||
// typed HasXxx() and ClearXxx() methods.
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1000,
|
||||
"snapOnInput": false
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
|
||||
// HasSetting should match HasXxx for set values
|
||||
VERIFY_ARE_EQUAL(profile.HasHistorySize(), profileImpl->HasSetting(implementation::ProfileSettingKey::HistorySize));
|
||||
VERIFY_ARE_EQUAL(profile.HasSnapOnInput(), profileImpl->HasSetting(implementation::ProfileSettingKey::SnapOnInput));
|
||||
|
||||
// HasSetting should match HasXxx for unset values
|
||||
VERIFY_ARE_EQUAL(profile.HasTabTitle(), profileImpl->HasSetting(implementation::ProfileSettingKey::TabTitle));
|
||||
VERIFY_IS_FALSE(profileImpl->HasSetting(implementation::ProfileSettingKey::TabTitle));
|
||||
|
||||
// ClearSetting should behave like ClearXxx
|
||||
profileImpl->ClearSetting(implementation::ProfileSettingKey::HistorySize);
|
||||
VERIFY_IS_FALSE(profile.HasHistorySize());
|
||||
VERIFY_IS_FALSE(profileImpl->HasSetting(implementation::ProfileSettingKey::HistorySize));
|
||||
}
|
||||
|
||||
void ProfileTests::CurrentSettingsReturnsCorrectKeys()
|
||||
{
|
||||
// Verify that CurrentSettings() returns the keys that are explicitly
|
||||
// set at the current layer.
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1000,
|
||||
"snapOnInput": false,
|
||||
"tabTitle": "MyTab"
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
|
||||
const auto currentKeys = profileImpl->CurrentSettings();
|
||||
|
||||
// historySize, snapOnInput, and tabTitle should be in the list
|
||||
auto hasHistorySize = false;
|
||||
auto hasSnapOnInput = false;
|
||||
auto hasTabTitle = false;
|
||||
for (const auto& key : currentKeys)
|
||||
{
|
||||
if (key == implementation::ProfileSettingKey::HistorySize)
|
||||
{
|
||||
hasHistorySize = true;
|
||||
}
|
||||
if (key == implementation::ProfileSettingKey::SnapOnInput)
|
||||
{
|
||||
hasSnapOnInput = true;
|
||||
}
|
||||
if (key == implementation::ProfileSettingKey::TabTitle)
|
||||
{
|
||||
hasTabTitle = true;
|
||||
}
|
||||
}
|
||||
VERIFY_IS_TRUE(hasHistorySize, L"historySize should be in CurrentSettings");
|
||||
VERIFY_IS_TRUE(hasSnapOnInput, L"snapOnInput should be in CurrentSettings");
|
||||
VERIFY_IS_TRUE(hasTabTitle, L"tabTitle should be in CurrentSettings");
|
||||
|
||||
// Clear one and verify it's removed
|
||||
profileImpl->ClearSetting(implementation::ProfileSettingKey::TabTitle);
|
||||
const auto updatedKeys = profileImpl->CurrentSettings();
|
||||
auto hasTabTitleAfterClear = false;
|
||||
for (const auto& key : updatedKeys)
|
||||
{
|
||||
if (key == implementation::ProfileSettingKey::TabTitle)
|
||||
{
|
||||
hasTabTitleAfterClear = true;
|
||||
}
|
||||
}
|
||||
VERIFY_IS_FALSE(hasTabTitleAfterClear, L"tabTitle should NOT be in CurrentSettings after clear");
|
||||
}
|
||||
|
||||
void ProfileTests::SpecialCasedSettingsJsonBacked()
|
||||
{
|
||||
// Verify that special-cased settings (Name, Guid, Hidden, Padding)
|
||||
// are now JSON-backed: setters write to _json, Has/Clear work correctly.
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "TestProfile",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"hidden": true,
|
||||
"padding": "12"
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
|
||||
// Verify initial values loaded from JSON
|
||||
VERIFY_ARE_EQUAL(L"TestProfile", profile.Name());
|
||||
VERIFY_IS_TRUE(profile.HasName());
|
||||
VERIFY_IS_TRUE(profile.Hidden());
|
||||
VERIFY_IS_TRUE(profile.HasHidden());
|
||||
VERIFY_ARE_EQUAL(L"12", profile.Padding());
|
||||
VERIFY_IS_TRUE(profile.HasPadding());
|
||||
|
||||
// Modify Name via setter — should update _json
|
||||
profile.Name(L"NewName");
|
||||
VERIFY_ARE_EQUAL(L"NewName", profile.Name());
|
||||
const auto json1 = profileImpl->ToJson();
|
||||
VERIFY_ARE_EQUAL(L"NewName", til::u8u16(json1["name"].asString()));
|
||||
|
||||
// Clear Name — should fall back to default
|
||||
profile.ClearName();
|
||||
VERIFY_IS_FALSE(profile.HasName());
|
||||
VERIFY_ARE_EQUAL(L"Default", profile.Name());
|
||||
|
||||
// Modify Hidden via setter
|
||||
profile.Hidden(false);
|
||||
VERIFY_ARE_EQUAL(false, profile.Hidden());
|
||||
VERIFY_IS_TRUE(profile.HasHidden());
|
||||
|
||||
// Clear Hidden — should fall back to default (false)
|
||||
profile.ClearHidden();
|
||||
VERIFY_IS_FALSE(profile.HasHidden());
|
||||
VERIFY_ARE_EQUAL(false, profile.Hidden());
|
||||
|
||||
// Modify Padding — should write to _json
|
||||
profile.Padding(L"24");
|
||||
VERIFY_ARE_EQUAL(L"24", profile.Padding());
|
||||
|
||||
// Test Guid setter
|
||||
static constexpr winrt::guid testGuid{ 0x11111111, 0x2222, 0x3333, { 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77 } };
|
||||
profile.Guid(testGuid);
|
||||
VERIFY_ARE_EQUAL(testGuid, profile.Guid());
|
||||
}
|
||||
|
||||
void ProfileTests::NullableSettingJsonBacked()
|
||||
{
|
||||
// Verify that nullable settings (TabColor) are JSON-backed.
|
||||
// Null is a valid explicit value meaning "no color".
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"tabColor": "#FF0000"
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
|
||||
// Verify initial value
|
||||
VERIFY_IS_TRUE(profile.HasTabColor());
|
||||
VERIFY_IS_NOT_NULL(profile.TabColor());
|
||||
|
||||
// Set to null explicitly (means "no color")
|
||||
profile.TabColor(nullptr);
|
||||
VERIFY_IS_TRUE(profile.HasTabColor()); // still "set" — explicitly null
|
||||
VERIFY_IS_NULL(profile.TabColor());
|
||||
|
||||
// Clear — should inherit from parent (which has no tabColor)
|
||||
profile.ClearTabColor();
|
||||
VERIFY_IS_FALSE(profile.HasTabColor());
|
||||
|
||||
// ToJson should not have tabColor after clearing
|
||||
const auto json = profileImpl->ToJson();
|
||||
VERIFY_IS_FALSE(json.isMember("tabColor"));
|
||||
}
|
||||
|
||||
void ProfileTests::ColorSchemeJsonBacked()
|
||||
{
|
||||
// Verify that DarkColorSchemeName/LightColorSchemeName are JSON-backed,
|
||||
// including round-trip through LayerJson/ToJson, parent inheritance,
|
||||
// and the polymorphic colorScheme key (string vs object forms).
|
||||
|
||||
// Case 1: string form input — sets both dark and light to the same scheme
|
||||
{
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"colorScheme": "One Half Dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
const auto appearance = profile.DefaultAppearance();
|
||||
const auto appearanceImpl = winrt::get_self<implementation::AppearanceConfig>(appearance);
|
||||
|
||||
// Both dark and light should be set to the same value
|
||||
VERIFY_ARE_EQUAL(L"One Half Dark", appearance.DarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(L"One Half Dark", appearance.LightColorSchemeName());
|
||||
VERIFY_IS_TRUE(appearanceImpl->HasDarkColorSchemeName());
|
||||
VERIFY_IS_TRUE(appearanceImpl->HasLightColorSchemeName());
|
||||
|
||||
// ToJson should collapse to a string since dark == light
|
||||
const auto json = profileImpl->ToJson();
|
||||
VERIFY_IS_TRUE(json.isMember("colorScheme"));
|
||||
VERIFY_IS_TRUE(json["colorScheme"].isString());
|
||||
VERIFY_ARE_EQUAL("One Half Dark", json["colorScheme"].asString());
|
||||
}
|
||||
|
||||
// Case 2: object form input — dark and light are different
|
||||
{
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"colorScheme": {
|
||||
"dark": "One Half Dark",
|
||||
"light": "One Half Light"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
const auto appearance = profile.DefaultAppearance();
|
||||
const auto appearanceImpl = winrt::get_self<implementation::AppearanceConfig>(appearance);
|
||||
|
||||
// Each should return its own value
|
||||
VERIFY_ARE_EQUAL(L"One Half Dark", appearance.DarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(L"One Half Light", appearance.LightColorSchemeName());
|
||||
|
||||
// ToJson should produce an object since dark != light
|
||||
const auto json = profileImpl->ToJson();
|
||||
VERIFY_IS_TRUE(json.isMember("colorScheme"));
|
||||
VERIFY_IS_TRUE(json["colorScheme"].isObject());
|
||||
VERIFY_ARE_EQUAL("One Half Dark", json["colorScheme"]["dark"].asString());
|
||||
VERIFY_ARE_EQUAL("One Half Light", json["colorScheme"]["light"].asString());
|
||||
}
|
||||
|
||||
// Case 3: setter updates — setting dark should preserve light, and vice versa
|
||||
{
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"colorScheme": "Campbell"
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
const auto appearance = profile.DefaultAppearance();
|
||||
const auto appearanceImpl = winrt::get_self<implementation::AppearanceConfig>(appearance);
|
||||
|
||||
// Change dark only — light should stay "Campbell"
|
||||
appearance.DarkColorSchemeName(L"Tango Dark");
|
||||
VERIFY_ARE_EQUAL(L"Tango Dark", appearance.DarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(L"Campbell", appearance.LightColorSchemeName());
|
||||
|
||||
// ToJson should produce an object since dark != light
|
||||
const auto json1 = profileImpl->ToJson();
|
||||
VERIFY_IS_TRUE(json1["colorScheme"].isObject());
|
||||
VERIFY_ARE_EQUAL("Tango Dark", json1["colorScheme"]["dark"].asString());
|
||||
VERIFY_ARE_EQUAL("Campbell", json1["colorScheme"]["light"].asString());
|
||||
|
||||
// Change light to match dark — should collapse to string on ToJson
|
||||
appearance.LightColorSchemeName(L"Tango Dark");
|
||||
VERIFY_ARE_EQUAL(L"Tango Dark", appearance.LightColorSchemeName());
|
||||
const auto json2 = profileImpl->ToJson();
|
||||
VERIFY_IS_TRUE(json2["colorScheme"].isString());
|
||||
VERIFY_ARE_EQUAL("Tango Dark", json2["colorScheme"].asString());
|
||||
}
|
||||
|
||||
// Case 4: clear — removes colorScheme entirely, falls back to default "Campbell"
|
||||
{
|
||||
static constexpr std::string_view settingsJson{ R"({
|
||||
"profiles": {
|
||||
"list": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"colorScheme": "One Half Dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
})" };
|
||||
|
||||
const auto settings = winrt::make_self<implementation::CascadiaSettings>(settingsJson);
|
||||
const auto profile = settings->AllProfiles().GetAt(0);
|
||||
const auto profileImpl = winrt::get_self<implementation::Profile>(profile);
|
||||
const auto appearance = profile.DefaultAppearance();
|
||||
const auto appearanceImpl = winrt::get_self<implementation::AppearanceConfig>(appearance);
|
||||
|
||||
VERIFY_IS_TRUE(appearanceImpl->HasDarkColorSchemeName());
|
||||
|
||||
// Clear removes colorScheme from this layer
|
||||
appearanceImpl->ClearDarkColorSchemeName();
|
||||
VERIFY_IS_FALSE(appearanceImpl->HasDarkColorSchemeName());
|
||||
VERIFY_IS_FALSE(appearanceImpl->HasLightColorSchemeName());
|
||||
|
||||
// Falls back to default "Campbell"
|
||||
VERIFY_ARE_EQUAL(L"Campbell", appearance.DarkColorSchemeName());
|
||||
VERIFY_ARE_EQUAL(L"Campbell", appearance.LightColorSchemeName());
|
||||
|
||||
// ToJson should not have colorScheme
|
||||
const auto json = profileImpl->ToJson();
|
||||
VERIFY_IS_FALSE(json.isMember("colorScheme"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,29 +315,16 @@ AppHost* WindowEmperor::_mostRecentWindow() const noexcept
|
||||
|
||||
void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
{
|
||||
// When running without package identity, set an explicit AppUserModelID so
|
||||
// that toast notifications (and other shell features like taskbar grouping)
|
||||
// work correctly. We include...
|
||||
// - a hash of the executable path
|
||||
// - a hash of the user SID
|
||||
// This prevents crosstalk between different portable/unpackaged installations.
|
||||
// The same isolation strategy is used for the single-instance mutex below.
|
||||
std::wstring unpackagedAumid;
|
||||
|
||||
std::wstring windowClassName;
|
||||
windowClassName.reserve(64); // "Windows Terminal Preview Admin 0123456789012345 0123456789012345"
|
||||
#if defined(WT_BRANDING_RELEASE)
|
||||
windowClassName.append(L"Windows Terminal");
|
||||
unpackagedAumid = L"Microsoft.WindowsTerminal";
|
||||
#elif defined(WT_BRANDING_PREVIEW)
|
||||
windowClassName.append(L"Windows Terminal Preview");
|
||||
unpackagedAumid = L"Microsoft.WindowsTerminalPreview";
|
||||
#elif defined(WT_BRANDING_CANARY)
|
||||
windowClassName.append(L"Windows Terminal Canary");
|
||||
unpackagedAumid = L"Microsoft.WindowsTerminalCanary";
|
||||
#else
|
||||
windowClassName.append(L"Windows Terminal Dev");
|
||||
unpackagedAumid = L"WindowsTerminalDev";
|
||||
#endif
|
||||
if (Utils::IsRunningElevated())
|
||||
{
|
||||
@@ -349,10 +336,8 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
const auto hash = til::hash(path);
|
||||
#ifdef _WIN64
|
||||
fmt::format_to(std::back_inserter(windowClassName), FMT_COMPILE(L" {:016x}"), hash);
|
||||
fmt::format_to(std::back_inserter(unpackagedAumid), FMT_COMPILE(L".{:016x}"), hash);
|
||||
#else
|
||||
fmt::format_to(std::back_inserter(windowClassName), FMT_COMPILE(L" {:08x}"), hash);
|
||||
fmt::format_to(std::back_inserter(unpackagedAumid), FMT_COMPILE(L".{:08x}"), hash);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -366,15 +351,6 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
#else
|
||||
fmt::format_to(std::back_inserter(windowClassName), FMT_COMPILE(L" {:08x}"), hash);
|
||||
#endif
|
||||
if (!IsPackaged())
|
||||
{
|
||||
#ifdef _WIN64
|
||||
fmt::format_to(std::back_inserter(unpackagedAumid), FMT_COMPILE(L".{:016x}"), hash);
|
||||
#else
|
||||
fmt::format_to(std::back_inserter(unpackagedAumid), FMT_COMPILE(L".{:08x}"), hash);
|
||||
#endif
|
||||
LOG_IF_FAILED(SetCurrentProcessExplicitAppUserModelID(unpackagedAumid.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// Windows Terminal is a single-instance application. Either acquire ownership
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user