From da0b96a5ad04d78b6d0c8bd749454c37a4d717bd Mon Sep 17 00:00:00 2001 From: Tobias Sekan Date: Thu, 14 Oct 2021 16:17:41 +0200 Subject: [PATCH] [WindowsSettings] DevDocs + JSON schema (#13510) * #10997 - Added JSON schema and extra shell class * #13510 - Address feedback and fix wrong typo for a member * #13510 - Add DevDoc (first version) * #13510 - make spellcheck happy * #13510 Address feedback, add scores, replace todos * Make build server happy * #13510 - Address feedback - Extra table for keys * #13510 - Address feedback * #13510 -Address feedback, add language specified Co-authored-by: Sekan, Tobias --- .../launcher/plugins/windowssettings.md | 155 ++++++++++++++++++ .../Classes/WindowsSettings.cs | 28 ++++ .../Helper/JsonSettingsListHelper.cs | 8 +- .../Helper/TranslationHelper.cs | 10 +- .../Helper/UnsupportedSettingsHelper.cs | 15 +- .../Helper/WindowsSettingsPathHelper.cs | 14 +- .../Main.cs | 19 ++- .../WindowsSettings.json | 20 ++- .../WindowsSettings.schema.json | 65 ++++++++ 9 files changed, 292 insertions(+), 42 deletions(-) create mode 100644 doc/devdocs/modules/launcher/plugins/windowssettings.md create mode 100644 src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Classes/WindowsSettings.cs create mode 100644 src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/WindowsSettings.schema.json diff --git a/doc/devdocs/modules/launcher/plugins/windowssettings.md b/doc/devdocs/modules/launcher/plugins/windowssettings.md new file mode 100644 index 0000000000..aa8678577d --- /dev/null +++ b/doc/devdocs/modules/launcher/plugins/windowssettings.md @@ -0,0 +1,155 @@ +# Windows Settings Plugin + +The Windows settings Plugin allows users to search the Windows settings. + +## Special functions (differ from the regular functions) + +* Support modern Windows settings (Windows 10+) +* Support legacy Windows settings (Windows 7, 8.1) +* Support extra programs for setting (like ODBC) + +* Support search by the area of the setting (like `Privacy`) +* Support search for alternative names of a setting + +## How to add a new Windows Setting or change one + +All Windows settings are located in `WindowsSettings.json` in root folder of the project. +The `WindowsSettings.json` use a JSON schema file that make it easier to edit it. + +| Key | Optional | Value type | String prefix | +| ------------------- | -------- | ----------------- | ------------- | +| `Name` | **No** | String | | +| `Type` | **No** | String | `App` | +| `Command` | **No** | String | | +| `Areas` | Yes | List with strings | `Area` | +| `AltNames` | Yes | List with strings | | +| `Note` | Yes | String | `Note` | +| `IntroducedInBuild` | Yes | Integer | | +| `DeprecatedInBuild` | Yes | Integer | | + +A minimum entry for the `WindowsSettings.json` looks like: + +```json + { + "Name": "mySetting", + "Type": "AppSettingsApp", + "Command": "ms-settings:mySetting" + } +``` + +A full entry for the `WindowsSettings.json` looks like: + +```json + { + "Name": "mySetting", + "Type": "AppSettingsApp", + "Command": "ms-settings:mySetting", + "Areas": [ "AreaMySettingArea" ], + "AltNames": [ "NiceSetting" ], + "Note": "NoteMySettingNote", + "IntroducedInBuild" : 1903, + "DeprecatedInBuild" : 2004 + } +``` + +### Remarks + +* The `Command` for modern Windows settings should start with `ms-settings:` +* The `Command` for legacy Windows settings should start with `control` +* The integer value for `IntroducedInBuild` and `DeprecatedInBuild` must be in range of `0` to `4294967295` +* The strings for `Name`, `AltNames`, `Areas`, `Type` and `Note` must not contain whitespace(s) or special characters (#, €, $, etc.) +* The strings for `Name`, `AltNames`, `Areas`, `Type` and `Note` are used as ids for the resource file under `Properties\Resources.resx` +* When you add new strings make sure you have add add all translations for it. + +## Scores + +There are three different score types with different start values. + +| Score type | Start value | +| ------------ | ------------ | +| High score | 10000 | +| Medium score | 5000 | +| Low score | 1000 | + +Each score will decreased by one when a condition match. + +| Priority | Condition | Score type | +| -------- | ----------------------------------------------------------------- | ------------ | +| 1. | Settings name starts with the search value | High score | +| 2. | Settings name contain the search value | Medium score | +| 3. | Setting has no area | Low score | +| 4. | One area of the settings starts with the search value | Low score | +| 5. | Setting has no alternative name | Low score | +| 6. | One alternative name of the settings starts with the search value | Medium score | +| x. | no condition match | Low score | + +## Important for developers + +### General + +* The assembly name is cached into `_assemblyName` (to avoid to many calls of `Assembly.GetExecutingAssembly()`) + +## Microsoft.PowerToys.Run.Plugin.WindowsSettings project + +### Important plugin values (meta-data) + +| Name | Value | +| --------------- | ---------------------------------------------------- | +| ActionKeyword | `$` | +| ExecuteFileName | `Microsoft.PowerToys.Run.Plugin.WindowsSettings.dll` | +| ID | `5043CECEE6A748679CBE02D27D83747A` | + +### Interfaces used by this plugin + +The plugin use only these interfaces (all inside the `Main.cs`): + +* `Wox.Plugin.IPlugin` +* `Wox.Plugin.IContextMenu` +* `Wox.Plugin.IPluginI18n` + +### Program files + +| File | Content | +| ------------------------------------- | ----------------------------------------------------------------------- | +| `Classes\WindowsSetting.cs` | A class that represent one Windows setting | +| `Classes\WindowsSettings.cs` | A wrapper class that only contains a list with Windows settings (see 1) | +| `Helper\ContextMenuHelper.cs` | All functions to build the context menu (for each result entry) | +| `Helper\JsonSettingsListHelper.cs` | All functions to load the windows settings from a JSON file | +| `Helper\ResultHelper.cs` | All functions to convert internal results into WOX results | +| `Helper\TranslationHelper.cs` | All functions to translate the result in the surface language | +| `Helper\UnsupportedSettingsHelper.cs` | All functions to filter not supported Windows settings out | +| `Helper\WindowsSettingsPathHelper.cs` | All functions to build the area paths | +| `Images\WindowsSettings.dark.png` | Symbol for the results for the dark theme | +| `Images\WindowsSettings.light.png` | Symbol for the results for the light theme | +| `Properties\Resources.Designer.resx` | File that contain all translatable keys | +| `Properties\Resources.resx` | File that contain all translatable strings in the neutral language | +| `GlobalSuppressions.cs` | Code suppressions (no real file, linked via *.csproj) | +| `Main.cs` | Main class, the only place that implement the WOX interfaces | +| `plugin.json` | All meta-data for this plugin | +| `StyleCop.json` | Code style (no real file, linked via *.csproj) | + +1. We need this extra wrapper class to make it possible that the JSON file can have and use a JSON schema file. +Because the JSON file must have a object as root type, instead of a array. + +### Important project values (*.csproj) + +| Name | Value | +| --------------- | --------------------------------------------------------------------------------------------------- | +| TargetFramework | `netcoreapp3.1` (means .NET Core 3.1) | +| Platforms | `x64` | +| Output | `..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\` | +| RootNamespace | `Microsoft.PowerToys.Run.Plugin.WindowsSettings` | +| AssemblyName | `Microsoft.PowerToys.Run.Plugin.WindowsSettings` | + +### Project dependencies + +#### Packages + +| Package | Version | +| ------------------------------------------------------------------------------------- | ------- | +| [`StyleCop.Analyzers`](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) | 1.1.118 | + +#### Projects + +* `Wox.Infrastructure` +* `Wox.Plugin` diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Classes/WindowsSettings.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Classes/WindowsSettings.cs new file mode 100644 index 0000000000..7ce25eb499 --- /dev/null +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Classes/WindowsSettings.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings +{ + /// + /// A class that contain all possible windows settings + /// + internal class WindowsSettings + { + /// + /// Initializes a new instance of the class with an empty settings list. + /// + public WindowsSettings() + { + Settings = Enumerable.Empty(); + } + + /// + /// Gets or sets a list with all possible windows settings + /// + public IEnumerable Settings { get; set; } + } +} diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/JsonSettingsListHelper.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/JsonSettingsListHelper.cs index 32cddf0944..a9aea3566a 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/JsonSettingsListHelper.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/JsonSettingsListHelper.cs @@ -27,12 +27,12 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings.Helper /// Read all possible Windows settings. /// /// A list with all possible windows settings. - internal static IEnumerable ReadAllPossibleSettings() + internal static WindowsSettings ReadAllPossibleSettings() { var assembly = Assembly.GetExecutingAssembly(); var type = assembly.GetTypes().FirstOrDefault(x => x.Name == nameof(Main)); - IEnumerable? settingsList = null; + WindowsSettings? settings = null; try { @@ -49,14 +49,14 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings.Helper using var reader = new StreamReader(stream); var text = reader.ReadToEnd(); - settingsList = JsonSerializer.Deserialize>(text, options); + settings = JsonSerializer.Deserialize(text, options); } catch (Exception exception) { Log.Exception("Error loading settings JSON file", exception, typeof(JsonSettingsListHelper)); } - return settingsList ?? Enumerable.Empty(); + return settings ?? new WindowsSettings(); } } } diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/TranslationHelper.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/TranslationHelper.cs index 3645debdb6..e7beed3dda 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/TranslationHelper.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/TranslationHelper.cs @@ -16,17 +16,17 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings.Helper internal static class TranslationHelper { /// - /// Translate all settings of the given list with . + /// Translate all settings of the settings list in the given class. /// - /// The list that contains to translate. - internal static void TranslateAllSettings(in IEnumerable? settingsList) + /// A class that contain all possible windows settings. + internal static void TranslateAllSettings(in WindowsSettings windowsSettings) { - if (settingsList is null) + if (windowsSettings?.Settings is null) { return; } - foreach (var settings in settingsList) + foreach (var settings in windowsSettings.Settings) { // Translate Name if (!string.IsNullOrWhiteSpace(settings.Name)) diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/UnsupportedSettingsHelper.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/UnsupportedSettingsHelper.cs index d455067f46..713c59b41d 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/UnsupportedSettingsHelper.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/UnsupportedSettingsHelper.cs @@ -19,15 +19,14 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings.Helper private const string _keyNameBuildNumber = "CurrentBuildNumber"; /// - /// Remove all of the given list that are not present on the current used Windows build. + /// Remove all from the settings list in the given class. /// - /// The list with to filter. - /// A new list with that only contain present Windows settings for this OS. - internal static IEnumerable FilterByBuild(in IEnumerable? settingsList) + /// A class that contain all possible windows settings. + internal static void FilterByBuild(in WindowsSettings windowsSettings) { - if (settingsList is null) + if (windowsSettings?.Settings is null) { - return Enumerable.Empty(); + return; } var currentBuild = GetNumericRegistryValue(_keyPath, _keyNameBuild); @@ -48,13 +47,13 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings.Helper ? currentBuild : currentBuildNumber; - var filteredSettingsList = settingsList.Where(found + var filteredSettingsList = windowsSettings.Settings.Where(found => (found.DeprecatedInBuild == null || currentWindowsBuild < found.DeprecatedInBuild) && (found.IntroducedInBuild == null || currentWindowsBuild >= found.IntroducedInBuild)); filteredSettingsList = filteredSettingsList.OrderBy(found => found.Name); - return filteredSettingsList; + windowsSettings.Settings = filteredSettingsList; } /// diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/WindowsSettingsPathHelper.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/WindowsSettingsPathHelper.cs index 15c854c635..5c44c18e33 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/WindowsSettingsPathHelper.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Helper/WindowsSettingsPathHelper.cs @@ -19,17 +19,17 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings.Helper private const string _pathDelimiterSequence = "\u0020\u0020\u02C3\u0020\u0020"; // = "" /// - /// Generates the values for and on all settings of the given list with . + /// Generates the values for and on all settings of the list in the given class. /// - /// The list that contains to translate. - internal static void GenerateSettingsPathValues(in IEnumerable? settingsList) + /// A class that contain all possible windows settings. + internal static void GenerateSettingsPathValues(in WindowsSettings windowsSettings) { - if (settingsList is null) + if (windowsSettings?.Settings is null) { return; } - foreach (var settings in settingsList) + foreach (var settings in windowsSettings.Settings) { // Check if type value is filled. If not, then write log warning. if (string.IsNullOrEmpty(settings.Type)) @@ -52,9 +52,9 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings.Helper // Generating path values. if (!(settings.Areas is null) && settings.Areas.Any()) { - var areaValue = string.Join(WindowsSettingsPathHelper._pathDelimiterSequence, settings.Areas); + var areaValue = string.Join(_pathDelimiterSequence, settings.Areas); settings.JoinedAreaPath = areaValue; - settings.JoinedFullSettingsPath = $"{settings.Type}{WindowsSettingsPathHelper._pathDelimiterSequence}{areaValue}"; + settings.JoinedFullSettingsPath = $"{settings.Type}{_pathDelimiterSequence}{areaValue}"; } else { diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Main.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Main.cs index 25a706c1d2..827dd00ec9 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Main.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/Main.cs @@ -49,9 +49,9 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings private bool _disposed; /// - /// List that contain all settings. + /// A class that contain all possible windows settings. /// - private IEnumerable? _settingsList; + private WindowsSettings? _windowsSettings; /// /// Initializes a new instance of the class. @@ -82,11 +82,12 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings _context.API.ThemeChanged += OnThemeChanged; UpdateIconPath(_context.API.GetCurrentTheme()); - _settingsList = JsonSettingsListHelper.ReadAllPossibleSettings(); - _settingsList = UnsupportedSettingsHelper.FilterByBuild(_settingsList); + _windowsSettings = JsonSettingsListHelper.ReadAllPossibleSettings(); - TranslationHelper.TranslateAllSettings(_settingsList); - WindowsSettingsPathHelper.GenerateSettingsPathValues(_settingsList); + UnsupportedSettingsHelper.FilterByBuild(_windowsSettings); + + TranslationHelper.TranslateAllSettings(_windowsSettings); + WindowsSettingsPathHelper.GenerateSettingsPathValues(_windowsSettings); } /// @@ -95,13 +96,13 @@ namespace Microsoft.PowerToys.Run.Plugin.WindowsSettings /// The query to filter the list. /// A filtered list, can be empty when nothing was found. public List Query(Query query) - { - if (_settingsList is null) + { + if (_windowsSettings?.Settings is null) { return new List(0); } - var filteredList = _settingsList + var filteredList = _windowsSettings.Settings .Where(Predicate) .OrderBy(found => found.Name); diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/WindowsSettings.json b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/WindowsSettings.json index 4c80299e16..f227919699 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/WindowsSettings.json +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/WindowsSettings.json @@ -1,11 +1,13 @@ -[ - { - "Name": "AccessWorkOrSchool", - "Areas": [ "AreaAccounts" ], - "Type": "AppSettingsApp", - "AltNames": [ "Workplace" ], - "Command": "ms-settings:workplace" - }, +{ + "$schema" : "./WindowsSettings.schema.json", + "Settings": [ + { + "Name": "AccessWorkOrSchool", + "Areas": [ "AreaAccounts" ], + "Type": "AppSettingsApp", + "AltNames": [ "Workplace" ], + "Command": "ms-settings:workplace" + }, { "Name": "EmailAndAppAccounts", "Areas": [ "AreaAccounts" ], @@ -1734,4 +1736,4 @@ "AltNames": [ "wgpocpl.cpl" ], "Command": "control Wgpocpl.cpl" } -] +]} diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/WindowsSettings.schema.json b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/WindowsSettings.schema.json new file mode 100644 index 0000000000..2e7a281e11 --- /dev/null +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.WindowsSettings/WindowsSettings.schema.json @@ -0,0 +1,65 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "additionalProperties": false, + "required": [ "Settings" ], + "properties": { + "Settings": { + "description": "A list with all possible windows settings.", + "type": "array", + "items": { + "additionalProperties": false, + "required": [ "Name", "Command", "Type" ], + "type": "object", + "properties": { + "Name": { + "description": "The name of this setting.", + "type": "string" + }, + "Areas": { + "description": "A list of areas of this setting", + "type": "array", + "items": { + "description": "A area of this setting", + "type": "string", + "pattern": "^Area" + } + }, + "Type": { + "description": "The type of this setting.", + "type": "string", + "pattern": "^App" + }, + "AltNames": { + "description": "A list with alternative names for this setting", + "type": "array", + "items": { + "description": "A alternative name for this setting", + "type": "string" + } + }, + "Command": { + "description": "The command for this setting.", + "type": "string" + }, + "Note": { + "description": "A additional note for this setting.", + "type": "string", + "pattern": "^Note" + }, + "DeprecatedInBuild": { + "description": "The Windows build since this settings is not longer present.", + "type": "integer", + "minimum": 0, + "maximum": 4294967295 + }, + "IntroducedInBuild": { + "description": "The minimum need Windows build for this setting.", + "type": "integer", + "minimum": 0, + "maximum": 4294967295 + } + } + } + } + } +}