mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-09 20:57:22 +02:00
This upgrades to [v0.0.24](https://github.com/check-spelling/check-spelling/releases/tag/v0.0.24). A number of GitHub APIs are being turned off shortly, so you need to upgrade or various uncertain outcomes will occur. There's a new accessibility forbidden pattern: > Do not use `(click) here` links > For more information, see: > * https://www.w3.org/QA/Tips/noClickHere > * https://webaim.org/techniques/hypertext/link_text > * https://granicus.com/blog/why-click-here-links-are-bad/ > * https://heyoka.medium.com/dont-use-click-here-f32f445d1021 ```pl (?i)(?:>|\[)(?:(?:click |)here|link|(?:read |)more)(?:</|\]\() ``` There are some minor bugs that I'm aware of and which I've fixed since this release, but I don't expect to make another release this month. I've added a pair of patterns for includes and pragmas. My argument is that the **compiler** will _generally_ tell you if you've misspelled an include and the **linker** will _generally_ tell you if you misspell a lib. - There's a caveat here: If your include case-insensitively matches the referenced file (but doesn't properly match it), then unless you either use a case-sensitive file system (as opposed to case-preserving) or beg clang to warn, you won't notice when you make this specific mistake -- this matters in that a couple of Windows headers (e.g. Unknwn.h) have particular case and repositories don't tend to consistently/properly write them.
286 lines
11 KiB
C#
286 lines
11 KiB
C#
// 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;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO.Abstractions;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows.Controls;
|
|
|
|
using ManagedCommon;
|
|
using Microsoft.Plugin.Indexer.DriveDetection;
|
|
using Microsoft.Plugin.Indexer.Interop;
|
|
using Microsoft.Plugin.Indexer.SearchHelper;
|
|
using Microsoft.PowerToys.Settings.UI.Library;
|
|
using Wox.Infrastructure;
|
|
using Wox.Infrastructure.Storage;
|
|
using Wox.Plugin;
|
|
using Wox.Plugin.Logger;
|
|
|
|
namespace Microsoft.Plugin.Indexer
|
|
{
|
|
internal class Main : ISettingProvider, IPlugin, ISavable, IPluginI18n, IContextMenu, IDisposable, IDelayedExecutionPlugin
|
|
{
|
|
private const string DisableDriveDetectionWarning = nameof(DisableDriveDetectionWarning);
|
|
private const string ExcludedPatterns = nameof(ExcludedPatterns);
|
|
private static readonly IFileSystem _fileSystem = new FileSystem();
|
|
|
|
// This variable contains metadata about the Plugin
|
|
private PluginInitContext _context;
|
|
|
|
// This variable contains information about the context menus
|
|
private IndexerSettings _settings;
|
|
|
|
// Contains information about the plugin stored in json format
|
|
private PluginJsonStorage<IndexerSettings> _storage;
|
|
|
|
// Excluded patterns settings
|
|
private List<string> _excludedPatterns = new List<string>();
|
|
|
|
// To access Windows Search functionalities
|
|
private static readonly OleDBSearch _search = new OleDBSearch();
|
|
private readonly WindowsSearchAPI _api = new WindowsSearchAPI(_search);
|
|
|
|
// To obtain information regarding the drives that are indexed
|
|
private readonly IndexerDriveDetection _driveDetection = new IndexerDriveDetection(new RegistryWrapper(), new DriveDetection.DriveInfoWrapper());
|
|
|
|
// Reserved keywords in oleDB
|
|
private readonly string reservedStringPattern = @"^[\/\\\$\%]+$|^.*[<>].*$";
|
|
|
|
private string WarningIconPath { get; set; }
|
|
|
|
public string Name => Properties.Resources.Microsoft_plugin_indexer_plugin_name;
|
|
|
|
public string Description => Properties.Resources.Microsoft_plugin_indexer_plugin_description;
|
|
|
|
public static string PluginID => "2140FC9819AD43A3A616E2735815C27C";
|
|
|
|
public IEnumerable<PluginAdditionalOption> AdditionalOptions => new List<PluginAdditionalOption>()
|
|
{
|
|
new PluginAdditionalOption()
|
|
{
|
|
Key = DisableDriveDetectionWarning,
|
|
DisplayLabel = Properties.Resources.disable_drive_detection_warning,
|
|
Value = false,
|
|
},
|
|
new PluginAdditionalOption()
|
|
{
|
|
PluginOptionType = PluginAdditionalOption.AdditionalOptionType.MultilineTextbox,
|
|
Key = ExcludedPatterns,
|
|
DisplayLabel = Properties.Resources.excluded_patterns_label,
|
|
DisplayDescription = Properties.Resources.excluded_patterns_description,
|
|
PlaceholderText = Properties.Resources.excluded_patterns_placeholder,
|
|
TextValue = string.Empty,
|
|
},
|
|
};
|
|
|
|
private ContextMenuLoader _contextMenuLoader;
|
|
private bool disposedValue;
|
|
|
|
// To save the configurations of plugins
|
|
public void Save()
|
|
{
|
|
_storage?.Save();
|
|
}
|
|
|
|
// This function uses the Windows indexer and returns the list of results obtained
|
|
public List<Result> Query(Query query, bool isFullQuery)
|
|
{
|
|
var results = new List<Result>();
|
|
|
|
if (!string.IsNullOrEmpty(query.Search))
|
|
{
|
|
var searchQuery = query.Search;
|
|
if (_settings.MaxSearchCount <= 0)
|
|
{
|
|
_settings.MaxSearchCount = 30;
|
|
}
|
|
|
|
var regexMatch = Regex.Match(searchQuery, reservedStringPattern);
|
|
|
|
if (!regexMatch.Success)
|
|
{
|
|
try
|
|
{
|
|
if (_driveDetection.DisplayWarning())
|
|
{
|
|
results.Add(new Result
|
|
{
|
|
Title = Properties.Resources.Microsoft_plugin_indexer_drivedetectionwarning,
|
|
SubTitle = Properties.Resources.Microsoft_plugin_indexer_disable_warning_in_settings,
|
|
IcoPath = WarningIconPath,
|
|
Action = e =>
|
|
{
|
|
Helper.OpenInShell("ms-settings:cortana-windowssearch");
|
|
return true;
|
|
},
|
|
});
|
|
}
|
|
|
|
// This uses the Microsoft.Search.Interop assembly
|
|
var searchManager = new CSearchManager();
|
|
var searchResultsList = _api.Search(searchQuery, searchManager, excludedPatterns: _excludedPatterns, maxCount: _settings.MaxSearchCount).ToList();
|
|
|
|
// If the delayed execution query is not required (since the SQL query is fast) return empty results
|
|
if (searchResultsList.Count == 0 && isFullQuery)
|
|
{
|
|
return new List<Result>();
|
|
}
|
|
|
|
foreach (var searchResult in searchResultsList)
|
|
{
|
|
var path = searchResult.Path;
|
|
|
|
// Using CurrentCulture since this is user facing
|
|
var toolTipTitle = string.Format(CultureInfo.CurrentCulture, "{0} : {1}", Properties.Resources.Microsoft_plugin_indexer_name, searchResult.Title);
|
|
var toolTipText = string.Format(CultureInfo.CurrentCulture, "{0} : {1}", Properties.Resources.Microsoft_plugin_indexer_path, path);
|
|
string workingDir = null;
|
|
if (_settings.UseLocationAsWorkingDir)
|
|
{
|
|
workingDir = _fileSystem.Path.GetDirectoryName(path);
|
|
}
|
|
|
|
Result r = new Result();
|
|
r.Title = searchResult.Title;
|
|
r.SubTitle = Properties.Resources.Microsoft_plugin_indexer_subtitle_header + ": " + path;
|
|
r.IcoPath = path;
|
|
r.ToolTipData = new ToolTipData(toolTipTitle, toolTipText);
|
|
r.Action = c =>
|
|
{
|
|
bool hide = true;
|
|
if (!Helper.OpenInShell(path, null, workingDir))
|
|
{
|
|
hide = false;
|
|
var name = $"Plugin: {_context.CurrentPluginMetadata.Name}";
|
|
var msg = Properties.Resources.Microsoft_plugin_indexer_file_open_failed;
|
|
_context.API.ShowMsg(name, msg, string.Empty);
|
|
}
|
|
|
|
return hide;
|
|
};
|
|
r.ContextData = searchResult;
|
|
|
|
// If the result is a directory, then its display should show a directory.
|
|
if (_fileSystem.Directory.Exists(path))
|
|
{
|
|
r.QueryTextDisplay = path;
|
|
}
|
|
|
|
results.Add(r);
|
|
}
|
|
}
|
|
catch (InvalidOperationException)
|
|
{
|
|
// The connection has closed, internal error of ExecuteReader()
|
|
// Not showing this exception to the users
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Exception("Something failed", ex, GetType());
|
|
}
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
// This function uses the Windows indexer and returns the list of results obtained. This version is required to implement the interface
|
|
public List<Result> Query(Query query)
|
|
{
|
|
// All plugins have to implement IPlugin interface. We return empty collection as we do not want any computation with constant search plugins.
|
|
return new List<Result>();
|
|
}
|
|
|
|
public void Init(PluginInitContext context)
|
|
{
|
|
// initialize the context of the plugin
|
|
_context = context;
|
|
_contextMenuLoader = new ContextMenuLoader(context);
|
|
_storage = new PluginJsonStorage<IndexerSettings>();
|
|
_settings = _storage.Load();
|
|
_context.API.ThemeChanged += OnThemeChanged;
|
|
UpdateIconPath(_context.API.GetCurrentTheme());
|
|
}
|
|
|
|
// Todo : Update with theme based IconPath
|
|
private void UpdateIconPath(Theme theme)
|
|
{
|
|
if (theme == Theme.Light || theme == Theme.HighContrastWhite)
|
|
{
|
|
WarningIconPath = "Images/Warning.light.png";
|
|
}
|
|
else
|
|
{
|
|
WarningIconPath = "Images/Warning.dark.png";
|
|
}
|
|
}
|
|
|
|
private void OnThemeChanged(Theme currentTheme, Theme newTheme)
|
|
{
|
|
UpdateIconPath(newTheme);
|
|
}
|
|
|
|
// Set the Plugin Title
|
|
public string GetTranslatedPluginTitle()
|
|
{
|
|
return Properties.Resources.Microsoft_plugin_indexer_plugin_name;
|
|
}
|
|
|
|
// Set the plugin Description
|
|
public string GetTranslatedPluginDescription()
|
|
{
|
|
return Properties.Resources.Microsoft_plugin_indexer_plugin_description;
|
|
}
|
|
|
|
public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
|
|
{
|
|
return _contextMenuLoader.LoadContextMenus(selectedResult);
|
|
}
|
|
|
|
public void UpdateSettings(PowerLauncherPluginSettings settings)
|
|
{
|
|
var driveDetection = false;
|
|
|
|
if (settings.AdditionalOptions != null)
|
|
{
|
|
var driveDetectionOption = settings.AdditionalOptions.FirstOrDefault(x => x.Key == DisableDriveDetectionWarning);
|
|
|
|
driveDetection = driveDetectionOption == null ? false : driveDetectionOption.Value;
|
|
|
|
var excludedPatternsOption = settings.AdditionalOptions.FirstOrDefault(x => x.Key == ExcludedPatterns);
|
|
|
|
_excludedPatterns = excludedPatternsOption == null ? new List<string>() : excludedPatternsOption.TextValueAsMultilineList;
|
|
}
|
|
|
|
_driveDetection.IsDriveDetectionWarningCheckBoxSelected = driveDetection;
|
|
}
|
|
|
|
public Control CreateSettingPanel()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!disposedValue)
|
|
{
|
|
if (disposing)
|
|
{
|
|
}
|
|
|
|
disposedValue = true;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|
Dispose(disposing: true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
}
|