From 015675d87c5902fe0391aa44cb5c76134f432b13 Mon Sep 17 00:00:00 2001 From: PankajBhojwani Date: Thu, 5 Nov 2020 16:43:16 -0500 Subject: [PATCH] Proto extensions spec (#7584) ## Summary of the Pull Request Proto-extensions spec ## PR Checklist * [x] Is documentation * [x] I work here * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx --- .../actions/spell-check/dictionary/apis.txt | 1 + .../spell-check/dictionary/dictionary.txt | 1 + doc/specs/Proto extensions-spec.md | 385 ++++++++++++++++++ 3 files changed, 387 insertions(+) create mode 100644 doc/specs/Proto extensions-spec.md diff --git a/.github/actions/spell-check/dictionary/apis.txt b/.github/actions/spell-check/dictionary/apis.txt index 9363cf513..4c94cd575 100644 --- a/.github/actions/spell-check/dictionary/apis.txt +++ b/.github/actions/spell-check/dictionary/apis.txt @@ -35,6 +35,7 @@ LCID llabs lround LSHIFT +msappx NCHITTEST NCLBUTTONDBLCLK NCRBUTTONDBLCLK diff --git a/.github/actions/spell-check/dictionary/dictionary.txt b/.github/actions/spell-check/dictionary/dictionary.txt index 23d5ba7cc..d15b22d85 100644 --- a/.github/actions/spell-check/dictionary/dictionary.txt +++ b/.github/actions/spell-check/dictionary/dictionary.txt @@ -313157,6 +313157,7 @@ post-Mishnical postmistress postmistresses postmistress-ship +postmodern postmortal post-mortem postmortem diff --git a/doc/specs/Proto extensions-spec.md b/doc/specs/Proto extensions-spec.md new file mode 100644 index 000000000..039da21d5 --- /dev/null +++ b/doc/specs/Proto extensions-spec.md @@ -0,0 +1,385 @@ +--- +author: <@PankajBhojwani> +created on: <2020-9-9> +last updated: <2020-10-15> +--- + +# Proto extensions + +## Abstract + +This spec outlines adding support for proto extensions. This would allow other apps/programs +to add json snippets to our json files, and will be used when we generate settings for our various profiles. + +## Inspiration + +### Goal: Allow programs to have a say in the settings for their profiles + +Currently, Ubuntu/WSL/Powershell etc are unable to provide any specifications for how they want +their profiles in Terminal to look - only we and the users can modify the profiles. We want to provide +these installations with the functionality to have a say in this, allowing them to specify things like +their icon, their font and so on. However, we want to maintain that the user has final say over all of +these settings. + +## Solution Design + +Currently, when we load the settings we perform the following steps (this is a simplified description, +for the full version see the [spec for cascading default + user settings](https://github.com/microsoft/terminal/blob/master/doc/specs/%23754%20-%20Cascading%20Default%20Settings.md)): + +1. Generate profiles from the defaults file +2. Generate profiles from the dynamic profile generators +3. Layer the user settings on top of all the profiles created in steps 1 and 2 +4. Validate the settings + +To allow for installations to add in their snippets of json, I propose the addition of a new step +in between 2 and 3: + +1. Generate profiles from the defaults file +2. Generate profiles from the dynamic profile generators +3. **Incorporate the additional provided json stubs** - these stubs could be: + 1. modifications to existing profiles + 2. additions of full profiles + 3. additions of colour schemes +4. Layer the user settings on top of all the profiles created in steps 1 through 3 (this includes the user-defined default settings which they wish to apply to all profiles) +5. Validate the settings + +### Specifications of the json stubs + +As written above, the json stubs could be modifications to existing profiles, additions to full profiles, or additions of colour schemes. + +To allow modifications/additions of several profiles in one file and to allow the addition of several colour schemes in one json file, +these stubs should be put into lists in the json file: one list named ```profiles``` and the other list named ```schemes```. For example: + +```js +{ + "profiles": [ modifications and additions of profiles go here ], + "schemes": [ additions of colour schemes go here ] +} +``` + +An example of a full json file with these fields filled out is shown at the end of this section. + +#### Modifications to existing profiles + +The main thing to note for modification of existing profiles is that this will only be used for modifying the +default profiles (cmd/powershell) or the dynamically generated profiles. + +For modifications to existing profiles, the json stub would need to indicate which profile it wishes to modify. It will +do this by providing the corresponding guid in the `"updates"` field of the json stub. The reason we use an `"updates"` +field rather than a `"guid"` field (like the way the user settings are eventually layered onto profiles) is because we +do not want to mistakenly create a new profile when the stub was meant to update a profile that did not exist. + +Note that currently, we generate a GUID for dynamic profiles using the "initial" name of the profile (i.e. before +any user changes are applied). For example, the "initial" name of a WSL profile is the \ argument to +"wsl.exe -d \", and the "initial" name of a Powershell profile is something like "Powershell (ARM)" - depending +on the version. Thus, the stub creator could simply use the same uuidv5 GUID generator we do on that name to obtain the +GUID. Then, in the stub they provide the GUID can be used to identify which profile to modify. + +Naturally, we will have to provide documentation on how they could generate the desired GUID themselves. In that documentation, +we will also provide examples showing how the current GUIDs are generated for clarity's sake. + +We need to inform developers that **we will not** prescribe any ordering to the way in which these modifications will be +applied - thus, they should not rely on their stub being the first/last to modify a particular profile (in the event that +there is more than one json stub modifying the same profile). + +Here is an example of a json file that modifies an existing profile (specifically the Azure cloud shell profile): + +```js +{ + "profiles": [ + { + "updates": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}", + "fontSize": 16, + "fontWeight": "thin" + } + ] +} +``` + +**NOTE**: This will *not* change the way the profile looks in the user's settings file. The Azure cloud shell profile +in their settings file (assuming they have made no changes) will still be as below. + +```js +{ + "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}", + "hidden": false, + "name": "Azure Cloud Shell", + "source": "Windows.Terminal.Azure" +} +``` +However, the user is free to make changes to it as usual and those changes will have the 'final say'. + +#### Full profile stubs + +Technically, full profile stubs do not need to contain anything (they could just be '\{\}'). However we should +have some qualifying minimum criteria before we accept a stub as a full profile. I suggest that we only create +new profile objects from stubs that contain at least the following + +* A name + +As in the case of the dynamic profile generator, if we create a profile that did not exist before (i.e. does not +exist in the user settings), we need to add the profile to the user settings file and re-save that file. + +Furthermore, we will add a source field to profiles created this way (again, similar to what we do for dynamic profiles). +The source field value is dependent on how we obtained this json file, and will be touched on in more detail [later in the spec](#the-source-field). + +Here is an example of a json file that contains a full profile: + +```js +{ + "profiles": [ + { + "guid": "{a821ae62-9d4a-3e34-b989-0a998ec283e6}", + "name": "Cool Profile", + "commandline": "powershell.exe", + "antialiasingMode": "aliased", + "fontWeight": "bold", + "scrollbarState": "hidden" + } + ] +} +``` + +When this profile gets added back to the user's settings file, it will look similar to the way we currently add +new dynamic profiles to the user's settings file. Going along with the example above, the corresponding +json stub in the user's settings file will be: + +```js +{ + "guid": "{a821ae62-9d4a-3e34-b989-0a998ec283e6}", + "name": "Cool Profile", + "hidden": "false", + "source": "local" +} +``` +Again, the user will be able to make changes to it as they do for all other profiles. + +#### Creation of colour schemes + +As with full profiles, we will have some qualifying criteria for what we accept as full colour schemes: color schemes +must have _all_ the fields that define a colour scheme - see the +[docs](https://docs.microsoft.com/en-us/windows/terminal/customize-settings/color-schemes) +on creating new colour schemes for what this means. + +This may cause the issue of colour schemes being overridden if there are many creations of a colour scheme with the +same name. Since for now all we have to uniquely identify colour schemes *is* the name, we will just let this be. + +Here is an example of a json stub that contains a colour scheme: + +```js +{ + "schemes": [ + { + "name": "Postmodern Tango Light", + + "cursorColor": "#FFFFFF", + "selectionBackground": "#FFFFFF", + + "background": '#61D6D6', + "foreground": '#E74856', + + "black" : "#0C0C0C", + "blue" : "#0037DA", + "cyan" : "#3A96DD", + "green" : "#13A10E", + "purple" : "#881798", + "red" : "#C50F1F", + "white" : "#CCCCCC", + "yellow" : "#C19C00", + "brightBlack" : "#767676", + "brightBlue" : "#3B78FF", + "brightCyan" : "#61D6D6", + "brightGreen" : "#16C60C", + "brightPurple" : "#B4009E", + "brightRed" : "#E74856", + "brightWhite" : "#F2F2F2", + "brightYellow" : "#F9F1A5" + } + ] +} +``` + +This stub will *not* show up in the users settings file, similar to the way our default colour schemes do not show up. + +#### Example of a full json file +This is an example of a json file that combines all the above examples. Thus, this json file modifies the Azure Cloud +Shell profile, creates a new profile called 'Cool Profile' and creates a new colour scheme called 'Postmodern Tango Light'. + +```js +{ + "profiles": [ + { + "updates": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}", + "fontSize": 16, + "fontWeight": "thin" + }, + { + "guid": "{a821ae62-9d4a-3e34-b989-0a998ec283e6}", + "name": "Cool Profile", + "commandline": "powershell.exe", + "antialiasingMode": "aliased", + "fontWeight": "bold", + "scrollbarState": "hidden" + } + ], + "schemes": [ + { + "name": "Postmodern Tango Light", + + "cursorColor": "#FFFFFF", + "selectionBackground": "#FFFFFF", + + "background": '#61D6D6', + "foreground": '#E74856', + + "black" : "#0C0C0C", + "blue" : "#0037DA", + "cyan" : "#3A96DD", + "green" : "#13A10E", + "purple" : "#881798", + "red" : "#C50F1F", + "white" : "#CCCCCC", + "yellow" : "#C19C00", + "brightBlack" : "#767676", + "brightBlue" : "#3B78FF", + "brightCyan" : "#61D6D6", + "brightGreen" : "#16C60C", + "brightPurple" : "#B4009E", + "brightRed" : "#E74856", + "brightWhite" : "#F2F2F2", + "brightYellow" : "#F9F1A5" + } + ] +} +``` + +### Creation and location(s) of the json files + +In this section, we cover where an app that wants to use this proto-extension functionality should put the json +files. Once we implement this feature, we will need to provide documentation on this for app developers. + +#### For apps installed through Microsoft store (or similar) + +For apps that are installed through something like the Microsoft Store, they will need to declare themselves to +be an app extension or write a separate app extension. In the app extension, they will need to create a public +folder, and create a subdirectory within that folder called `Fragments`. The json files should be inserted into the +`Fragments` subdirectory. The specifics of how they can declare themselves as an app extension are provided in the +[Microsoft Docs](https://docs.microsoft.com/en-us/windows/uwp/launch-resume/how-to-create-an-extension), and I will +replicate the necessary section here. + +In the appxmanifest file of the package: + +```js + + ... + + + ... + + ... + + + + + + + + ... + +``` + +Note that the name field **must** be `com.microsoft.windows.terminal.settings` for us to detect this extension. The `Id` field +can be filled out as the app wishes. The `PublicFolder` field should have the name of the folder, relative to +the package root, where the `json` files they wish to share with us are stored (this folder is typically named +`Public` but can be renamed as long as it matches the relevant folder). + +During our profile generation, we will probe the OS for app extensions with the name `com.microsoft.windows.terminal.settings` +and obtain the json files stored in the `Fragments` subdirectories of the public folders of those app extensions. + +#### For apps installed 'traditionally' + +For apps that are installed 'traditionally', there are 2 cases. The first is that this installation is for all +the users of the system - in this case, the installer should add their json files to the global folder: + +```js +C:\ProgramData\Microsoft\Windows Terminal\Fragments\{app-name} +``` + +Note: `C:\ProgramData` is a [known folder](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/bb776911(v=vs.85)) +that apps should be able to access. If the folder `Windows Terminal` in `C:\ProgramData\Microsoft\Windows` +does not already exist, the installer should create it. **Note:** the installer must create a subdirectory within +the `Fragments` folder with their app name, we will use that name for the [`source` field](#the-source-field). + +In the second case, the installation is only for the current user. For this case, the installer should add the +json files to the local folder: + +```js +C:\Users\\AppData\Local\Microsoft\Windows Terminal\Fragments\{app-name} +``` + +We will look through both folders mentioned above during profile generation. + +#### The source field + +Currently, we allow users an easy way to disable/enable profiles that are generated from certain sources. For +example, a user can easily hide all dynamic profiles with the source `"Windows.Terminal.Wsl"` if they wish to. +To retain this functionality, we will add source fields to profiles we create through proto-extensions. + +For full profiles that came from apps installed 'traditionally', we will use the name of the subdirectory where +the json file was found to fill out the source field. + +For full profiles that came from app extensions, we will use the app package name to fill out the source field. + + + +## UI/UX Design + +This feature will allow other installations a level of control over how their profiles look in Terminal. For example, +if Ubuntu gets a new icon or a new font they can have those changes be reflected in Terminal users' Ubuntu profiles. + +## Capabilities + +### Accessibility + +This change should not affect accessibility. + +### Security + +Opening a profile causes its commandline argument to be automatically run. Thus, if malicious modifications are made +to existing profiles or new profiles with malicious commandline arguments are added, users could be tricked into running +things they do not want to. + +### Reliability + +This should not affect reliability - most of what its doing is simply layering json which we already do. + +### Compatibility + +Again, there should not be any issues here - the user settings can still be layered after this layering for the user +to have the final say. + +### Performance, Power, and Efficiency + +Looking through the additional json files could negatively impact startup time. + +## Potential Issues + +* An installer dumps a _lot_ of json files into the folder which we need to look through. +* When a `.json` files is deleted, any new profiles that were generated from it remain in the user's settings file (though they no longer appear in the tab dropdown). + +## Future considerations + +We need to consider how an app extension provides the path to an image (for the icon source or background image of a profile for example) + +This will likely be a stepping stone for the theme marketplace. + +This will also likely be a stepping stone to allowing users to specify other files to import settings from. + +## Resources + +N/A