2020-08-17 10:00:56 -07:00
// 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 ;
2020-11-02 18:33:43 +01:00
using System.IO.Abstractions ;
2020-08-17 10:00:56 -07:00
using System.Linq ;
using System.Text.RegularExpressions ;
using System.Windows.Controls ;
2020-10-24 00:05:07 +02:00
using ManagedCommon ;
2020-08-17 10:00:56 -07:00
using Microsoft.Plugin.Indexer.DriveDetection ;
using Microsoft.Plugin.Indexer.SearchHelper ;
2020-10-22 09:45:48 -07:00
using Microsoft.PowerToys.Settings.UI.Library ;
2020-08-18 13:19:35 -07:00
using Microsoft.Search.Interop ;
2021-02-23 09:53:08 +01:00
using Wox.Infrastructure ;
2020-08-17 10:00:56 -07:00
using Wox.Infrastructure.Storage ;
using Wox.Plugin ;
2020-10-23 13:06:22 -07:00
using Wox.Plugin.Logger ;
2020-08-17 10:00:56 -07:00
namespace Microsoft.Plugin.Indexer
{
internal class Main : ISettingProvider , IPlugin , ISavable , IPluginI18n , IContextMenu , IDisposable , IDelayedExecutionPlugin
{
2021-02-26 13:21:58 +02:00
private const string DisableDriveDetectionWarning = nameof ( DisableDriveDetectionWarning ) ;
2020-11-02 18:33:43 +01:00
private static readonly IFileSystem _fileSystem = new FileSystem ( ) ;
2020-08-17 10:00:56 -07:00
// 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 ;
// 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
2020-11-02 18:33:43 +01:00
private readonly IndexerDriveDetection _driveDetection = new IndexerDriveDetection ( new RegistryWrapper ( ) , new DriveDetection . DriveInfoWrapper ( ) ) ;
2020-08-17 10:00:56 -07:00
// Reserved keywords in oleDB
2020-08-21 12:21:42 -07:00
private readonly string reservedStringPattern = @"^[\/\\\$\%]+$|^.*[<>].*$" ;
2020-08-17 10:00:56 -07:00
private string WarningIconPath { get ; set ; }
2021-02-26 13:21:58 +02:00
public string Name = > Properties . Resources . Microsoft_plugin_indexer_plugin_name ;
public string Description = > Properties . Resources . Microsoft_plugin_indexer_plugin_description ;
public IEnumerable < PluginAdditionalOption > AdditionalOptions = > new List < PluginAdditionalOption > ( )
{
new PluginAdditionalOption ( )
{
Key = DisableDriveDetectionWarning ,
DisplayLabel = Properties . Resources . disable_drive_detection_warning ,
Value = false ,
} ,
} ;
2020-08-17 10:00:56 -07:00
private IContextMenu _contextMenuLoader ;
private bool disposedValue ;
// To save the configurations of plugins
public void Save ( )
{
2021-05-31 13:00:06 +03:00
_storage ? . Save ( ) ;
2020-08-17 10:00:56 -07:00
}
// This function uses the Windows indexer and returns the list of results obtained
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive but will log the exception")]
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
{
2020-09-02 15:24:59 -07:00
Title = Properties . Resources . Microsoft_plugin_indexer_drivedetectionwarning ,
SubTitle = Properties . Resources . Microsoft_plugin_indexer_disable_warning_in_settings ,
2020-08-17 10:00:56 -07:00
IcoPath = WarningIconPath ,
Action = e = >
{
2021-02-23 09:53:08 +01:00
Helper . OpenInShell ( "ms-settings:cortana-windowssearch" ) ;
2020-08-17 10:00:56 -07:00
return true ;
} ,
} ) ;
}
2020-08-18 13:19:35 -07:00
// This uses the Microsoft.Search.Interop assembly
var searchManager = new CSearchManager ( ) ;
2020-12-14 18:07:26 +02:00
var searchResultsList = _api . Search ( searchQuery , searchManager , maxCount : _settings . MaxSearchCount ) . ToList ( ) ;
2020-08-17 10:00:56 -07:00
// 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 ;
2020-10-30 16:43:09 -07:00
// Using CurrentCulture since this is user facing
2020-09-02 15:24:59 -07:00
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 ) ;
2020-08-17 10:00:56 -07:00
string workingDir = null ;
if ( _settings . UseLocationAsWorkingDir )
{
2020-11-02 18:33:43 +01:00
workingDir = _fileSystem . Path . GetDirectoryName ( path ) ;
2020-08-17 10:00:56 -07:00
}
Result r = new Result ( ) ;
r . Title = searchResult . Title ;
2020-09-08 11:51:24 -07:00
r . SubTitle = Properties . Resources . Microsoft_plugin_indexer_subtitle_header + ": " + path ;
2020-08-17 10:00:56 -07:00
r . IcoPath = path ;
r . ToolTipData = new ToolTipData ( toolTipTitle , toolTipText ) ;
r . Action = c = >
{
2021-02-23 09:53:08 +01:00
bool hide = true ;
if ( ! Helper . OpenInShell ( path , null , workingDir ) )
2020-08-17 10:00:56 -07:00
{
2021-02-23 09:53:08 +01:00
hide = false ;
2020-08-17 10:00:56 -07:00
var name = $"Plugin: {_context.CurrentPluginMetadata.Name}" ;
2020-09-08 11:51:24 -07:00
var msg = Properties . Resources . Microsoft_plugin_indexer_file_open_failed ;
2020-08-17 10:00:56 -07:00
_context . API . ShowMsg ( name , msg , string . Empty ) ;
}
return hide ;
} ;
r . ContextData = searchResult ;
// If the result is a directory, then it's display should show a directory.
2020-11-02 18:33:43 +01:00
if ( _fileSystem . Directory . Exists ( path ) )
2020-08-17 10:00:56 -07:00
{
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 )
{
2020-09-23 16:32:06 -07:00
Log . Exception ( "Something failed" , ex , GetType ( ) ) ;
2020-08-17 10:00:56 -07:00
}
}
}
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 )
{
2020-12-14 18:07:26 +02:00
// 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 > ( ) ;
2020-08-17 10:00:56 -07:00
}
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 ( )
{
2020-09-08 11:51:24 -07:00
return Properties . Resources . Microsoft_plugin_indexer_plugin_name ;
2020-08-17 10:00:56 -07:00
}
// Set the plugin Description
public string GetTranslatedPluginDescription ( )
{
2020-09-08 11:51:24 -07:00
return Properties . Resources . Microsoft_plugin_indexer_plugin_description ;
2020-08-17 10:00:56 -07:00
}
public List < ContextMenuResult > LoadContextMenus ( Result selectedResult )
{
return _contextMenuLoader . LoadContextMenus ( selectedResult ) ;
}
2021-02-26 13:21:58 +02:00
public void UpdateSettings ( PowerLauncherPluginSettings settings )
2020-08-17 10:00:56 -07:00
{
2021-03-02 08:04:08 -08:00
var driveDetection = false ;
if ( settings . AdditionalOptions ! = null )
{
var option = settings . AdditionalOptions . FirstOrDefault ( x = > x . Key = = DisableDriveDetectionWarning ) ;
driveDetection = option = = null ? false : option . Value ;
}
_driveDetection . IsDriveDetectionWarningCheckBoxSelected = driveDetection ;
2020-08-17 10:00:56 -07:00
}
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 ) ;
}
}
}