2020-09-18 00:39:28 +02:00
// Copyright (c) Microsoft Corporation
2020-08-17 10:00:56 -07:00
// 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 ;
2020-10-07 18:23:47 +02:00
using System.Collections.Immutable ;
2020-08-17 10:00:56 -07:00
using System.Diagnostics ;
using System.Linq ;
using System.Threading.Tasks ;
2020-09-18 00:39:28 +02:00
using Microsoft.Plugin.Program.ProgramArgumentParser ;
2020-08-17 10:00:56 -07:00
using Microsoft.Plugin.Program.Programs ;
using Microsoft.Plugin.Program.Storage ;
using Wox.Infrastructure.Logger ;
using Wox.Infrastructure.Storage ;
using Wox.Plugin ;
using Stopwatch = Wox . Infrastructure . Stopwatch ;
namespace Microsoft.Plugin.Program
{
2020-07-09 13:14:53 -07:00
public class Main : IPlugin , IPluginI18n , IContextMenu , ISavable , IReloadable , IDisposable
2020-08-17 10:00:56 -07:00
{
2020-09-18 00:39:28 +02:00
// The order of this array is important! The Parsers will be checked in order (index 0 to index Length-1) and the first parser which is able to parse the Query will be used
// NoArgumentsArgumentParser does always succeed and therefor should always be last/fallback
private static readonly IProgramArgumentParser [ ] _programArgumentParsers = new IProgramArgumentParser [ ]
{
new DoubleDashProgramArgumentParser ( ) ,
new InferedProgramArgumentParser ( ) ,
new NoArgumentsArgumentParser ( ) ,
} ;
2020-08-17 10:00:56 -07:00
internal static ProgramPluginSettings Settings { get ; set ; }
private static PluginInitContext _context ;
private readonly PluginJsonStorage < ProgramPluginSettings > _settingsStorage ;
2020-08-21 12:40:31 -07:00
private bool _disposed ;
2020-08-11 09:08:44 -07:00
private PackageRepository _packageRepository = new PackageRepository ( new PackageCatalogWrapper ( ) , new BinaryStorage < IList < UWPApplication > > ( "UWP" ) ) ;
2020-07-17 22:32:21 -07:00
private static Win32ProgramFileSystemWatchers _win32ProgramRepositoryHelper ;
2020-08-17 10:00:56 -07:00
private static Win32ProgramRepository _win32ProgramRepository ;
public Main ( )
{
_settingsStorage = new PluginJsonStorage < ProgramPluginSettings > ( ) ;
Settings = _settingsStorage . Load ( ) ;
// This helper class initializes the file system watchers based on the locations to watch
_win32ProgramRepositoryHelper = new Win32ProgramFileSystemWatchers ( ) ;
// Initialize the Win32ProgramRepository with the settings object
_win32ProgramRepository = new Win32ProgramRepository ( _win32ProgramRepositoryHelper . FileSystemWatchers . Cast < IFileSystemWatcherWrapper > ( ) . ToList ( ) , new BinaryStorage < IList < Programs . Win32Program > > ( "Win32" ) , Settings , _win32ProgramRepositoryHelper . PathsToWatch ) ;
var a = Task . Run ( ( ) = >
{
2020-08-24 10:50:54 -07:00
Stopwatch . Normal ( "|Microsoft.Plugin.Program.Main|Win32Program index cost" , _win32ProgramRepository . IndexPrograms ) ;
2020-08-17 10:00:56 -07:00
} ) ;
var b = Task . Run ( ( ) = >
{
2020-08-24 10:50:54 -07:00
Stopwatch . Normal ( "|Microsoft.Plugin.Program.Main|Win32Program index cost" , _packageRepository . IndexPrograms ) ;
2020-08-17 10:00:56 -07:00
} ) ;
Task . WaitAll ( a , b ) ;
Settings . LastIndexTime = DateTime . Today ;
}
public void Save ( )
{
_settingsStorage . Save ( ) ;
}
public List < Result > Query ( Query query )
{
2020-10-07 18:23:47 +02:00
var sources = _programArgumentParsers
. Where ( programArgumentParser = > programArgumentParser . Enabled ) ;
2020-09-18 00:39:28 +02:00
2020-10-07 18:23:47 +02:00
foreach ( var programArgumentParser in sources )
{
2020-09-18 00:39:28 +02:00
if ( ! programArgumentParser . TryParse ( query , out var program , out var programArguments ) )
{
continue ;
}
2020-10-07 18:23:47 +02:00
return Query ( program , programArguments ) . ToList ( ) ;
}
2020-09-18 00:39:28 +02:00
2020-10-07 18:23:47 +02:00
return new List < Result > ( 0 ) ;
}
2020-09-18 00:39:28 +02:00
2020-10-07 18:23:47 +02:00
private IEnumerable < Result > Query ( string program , string programArguments )
{
var result = _win32ProgramRepository
. Concat < IProgram > ( _packageRepository )
. AsParallel ( )
. Where ( p = > p . Enabled )
. Select ( p = > p . Result ( program , programArguments , _context . API ) )
. Where ( r = > r ? . Score > 0 )
. ToArray ( ) ;
if ( result . Any ( ) )
{
var maxScore = result . Max ( x = > x . Score ) ;
return result
. Where ( x = > x . Score > Settings . MinScoreThreshold * maxScore ) ;
2020-08-19 16:16:45 -07:00
}
2020-08-17 10:00:56 -07:00
2020-10-07 18:23:47 +02:00
return Enumerable . Empty < Result > ( ) ;
2020-08-17 10:00:56 -07:00
}
public void Init ( PluginInitContext context )
{
_context = context ? ? throw new ArgumentNullException ( nameof ( context ) ) ;
_context . API . ThemeChanged + = OnThemeChanged ;
UpdateUWPIconPath ( _context . API . GetCurrentTheme ( ) ) ;
}
public void OnThemeChanged ( Theme currentTheme , Theme newTheme )
{
UpdateUWPIconPath ( newTheme ) ;
}
public void UpdateUWPIconPath ( Theme theme )
{
foreach ( UWPApplication app in _packageRepository )
{
app . UpdatePath ( theme ) ;
}
}
public void IndexPrograms ( )
{
var t1 = Task . Run ( ( ) = > _win32ProgramRepository . IndexPrograms ( ) ) ;
var t2 = Task . Run ( ( ) = > _packageRepository . IndexPrograms ( ) ) ;
Task . WaitAll ( t1 , t2 ) ;
Settings . LastIndexTime = DateTime . Today ;
}
public string GetTranslatedPluginTitle ( )
{
2020-09-02 15:24:59 -07:00
return Properties . Resources . wox_plugin_program_plugin_name ;
2020-08-17 10:00:56 -07:00
}
public string GetTranslatedPluginDescription ( )
{
2020-09-02 15:24:59 -07:00
return Properties . Resources . wox_plugin_program_plugin_description ;
2020-08-17 10:00:56 -07:00
}
public List < ContextMenuResult > LoadContextMenus ( Result selectedResult )
{
if ( selectedResult = = null )
{
throw new ArgumentNullException ( nameof ( selectedResult ) ) ;
}
var menuOptions = new List < ContextMenuResult > ( ) ;
if ( selectedResult . ContextData is Programs . IProgram program )
{
menuOptions = program . ContextMenus ( _context . API ) ;
}
return menuOptions ;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "We want to keep the process alive and show the user a warning message")]
public static void StartProcess ( Func < ProcessStartInfo , Process > runProcess , ProcessStartInfo info )
{
try
{
if ( runProcess = = null )
{
throw new ArgumentNullException ( nameof ( runProcess ) ) ;
}
if ( info = = null )
{
throw new ArgumentNullException ( nameof ( info ) ) ;
}
runProcess ( info ) ;
}
catch ( Exception )
{
2020-09-08 11:51:24 -07:00
var name = "Plugin: " + Properties . Resources . wox_plugin_program_plugin_name ;
var message = $"{Properties.Resources.powertoys_run_plugin_program_start_failed}: {info?.FileName}" ;
2020-08-17 10:00:56 -07:00
_context . API . ShowMsg ( name , message , string . Empty ) ;
}
}
public void ReloadData ( )
{
IndexPrograms ( ) ;
}
2020-06-26 17:42:06 -07:00
public void Dispose ( )
{
Dispose ( disposing : true ) ;
GC . SuppressFinalize ( this ) ;
}
protected virtual void Dispose ( bool disposing )
{
if ( ! _disposed )
{
if ( disposing )
{
_context . API . ThemeChanged - = OnThemeChanged ;
2020-07-17 22:32:21 -07:00
_win32ProgramRepositoryHelper . Dispose ( ) ;
2020-06-26 17:42:06 -07:00
_disposed = true ;
}
}
}
2020-08-17 10:00:56 -07:00
}
}