Merge branch 'dev' into ExplorerDirectorySearchWithIndexFix

This commit is contained in:
Jeremy Wu 2021-01-24 20:52:10 +11:00
commit 288baa5538
7 changed files with 46 additions and 48 deletions

View file

@ -60,8 +60,8 @@ namespace Flow.Launcher.Test.Plugins
$"Actual: {result}{Environment.NewLine}"); $"Actual: {result}{Environment.NewLine}");
} }
[TestCase("C:\\", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType FROM SystemIndex WHERE directory='file:C:\\'")] [TestCase("C:\\", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType FROM SystemIndex WHERE directory='file:C:\\' ORDER BY System.FileName")]
[TestCase("C:\\SomeFolder\\", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType FROM SystemIndex WHERE directory='file:C:\\SomeFolder\\'")] [TestCase("C:\\SomeFolder\\", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType FROM SystemIndex WHERE directory='file:C:\\SomeFolder\\' ORDER BY System.FileName")]
public void GivenWindowsIndexSearch_WhenSearchTypeIsTopLevelDirectorySearch_ThenQueryShouldUseExpectedString(string folderPath, string expectedString) public void GivenWindowsIndexSearch_WhenSearchTypeIsTopLevelDirectorySearch_ThenQueryShouldUseExpectedString(string folderPath, string expectedString)
{ {
// Given // Given
@ -79,7 +79,7 @@ namespace Flow.Launcher.Test.Plugins
[TestCase("C:\\SomeFolder\\flow.launcher.sln", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType " + [TestCase("C:\\SomeFolder\\flow.launcher.sln", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType " +
"FROM SystemIndex WHERE (System.FileName LIKE 'flow.launcher.sln%' " + "FROM SystemIndex WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
"OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033))" + "OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033))" +
" AND directory='file:C:\\SomeFolder'")] " AND directory='file:C:\\SomeFolder' ORDER BY System.FileName")]
public void GivenWindowsIndexSearchTopLevelDirectory_WhenSearchingForSpecificItem_ThenQueryShouldUseExpectedString( public void GivenWindowsIndexSearchTopLevelDirectory_WhenSearchingForSpecificItem_ThenQueryShouldUseExpectedString(
string userSearchString, string expectedString) string userSearchString, string expectedString)
{ {
@ -116,11 +116,8 @@ namespace Flow.Launcher.Test.Plugins
[TestCase("scope='file:'")] [TestCase("scope='file:'")]
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryWhereRestrictionsShouldUseScopeString(string expectedString) public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryWhereRestrictionsShouldUseScopeString(string expectedString)
{ {
// Given
var queryConstructor = new QueryConstructor(new Settings());
//When //When
var resultString = queryConstructor.QueryWhereRestrictionsForAllFilesAndFoldersSearch(); var resultString = QueryConstructor.QueryWhereRestrictionsForAllFilesAndFoldersSearch;
// Then // Then
Assert.IsTrue(resultString == expectedString, Assert.IsTrue(resultString == expectedString,
@ -130,7 +127,7 @@ namespace Flow.Launcher.Test.Plugins
[TestCase("flow.launcher.sln", "SELECT TOP 100 \"System.FileName\", \"System.ItemUrl\", \"System.ItemType\" " + [TestCase("flow.launcher.sln", "SELECT TOP 100 \"System.FileName\", \"System.ItemUrl\", \"System.ItemType\" " +
"FROM \"SystemIndex\" WHERE (System.FileName LIKE 'flow.launcher.sln%' " + "FROM \"SystemIndex\" WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
"OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033)) AND scope='file:'")] "OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033)) AND scope='file:' ORDER BY System.FileName")]
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryShouldUseExpectedString( public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryShouldUseExpectedString(
string userSearchString, string expectedString) string userSearchString, string expectedString)
{ {
@ -205,7 +202,7 @@ namespace Flow.Launcher.Test.Plugins
} }
[TestCase("some words", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType " + [TestCase("some words", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType " +
"FROM SystemIndex WHERE FREETEXT('some words') AND scope='file:'")] "FROM SystemIndex WHERE FREETEXT('some words') AND scope='file:' ORDER BY System.FileName")]
public void GivenWindowsIndexSearch_WhenSearchForFileContent_ThenQueryShouldUseExpectedString( public void GivenWindowsIndexSearch_WhenSearchForFileContent_ThenQueryShouldUseExpectedString(
string userSearchString, string expectedString) string userSearchString, string expectedString)
{ {
@ -298,9 +295,9 @@ namespace Flow.Launcher.Test.Plugins
} }
[TestCase("c:\\SomeFolder\\>", "scope='file:c:\\SomeFolder'")] [TestCase("c:\\SomeFolder\\>", "scope='file:c:\\SomeFolder'")]
[TestCase("c:\\SomeFolder\\>SomeName", "(System.FileName LIKE 'SomeName%' " + [TestCase("c:\\SomeFolder\\>SomeName", "(System.FileName LIKE 'SomeName%' "
"OR CONTAINS(System.FileName,'\"SomeName*\"',1033)) AND " + + "OR CONTAINS(System.FileName,'\"SomeName*\"',1033)) AND "
"scope='file:c:\\SomeFolder'")] + "scope='file:c:\\SomeFolder'")]
public void GivenWindowsIndexSearch_WhenSearchPatternHotKeyIsSearchAll_ThenQueryWhereRestrictionsShouldUseScopeString(string path, string expectedString) public void GivenWindowsIndexSearch_WhenSearchPatternHotKeyIsSearchAll_ThenQueryWhereRestrictionsShouldUseScopeString(string path, string expectedString)
{ {
// Given // Given

View file

@ -1,4 +1,4 @@
using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.Logger;
using Microsoft.Search.Interop; using Microsoft.Search.Interop;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -15,7 +15,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
private readonly ResultManager resultManager; private readonly ResultManager resultManager;
// Reserved keywords in oleDB // Reserved keywords in oleDB
private readonly string reservedStringPattern = @"^[\/\\\$\%_]+$"; private readonly string reservedStringPattern = @"^[`\@\#\^,\&\/\\\$\%_]+$";
internal IndexSearch(PluginInitContext context) internal IndexSearch(PluginInitContext context)
{ {
@ -24,9 +24,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
internal async Task<List<Result>> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token) internal async Task<List<Result>> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token)
{ {
var folderResults = new List<Result>();
var fileResults = new List<Result>();
var results = new List<Result>(); var results = new List<Result>();
var fileResults = new List<Result>();
try try
{ {
@ -55,7 +54,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
if (dataReaderResults.GetString(2) == "Directory") if (dataReaderResults.GetString(2) == "Directory")
{ {
folderResults.Add(resultManager.CreateFolderResult( results.Add(resultManager.CreateFolderResult(
dataReaderResults.GetString(0), dataReaderResults.GetString(0),
path, path,
path, path,
@ -83,8 +82,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
LogException("General error from performing index search", e); LogException("General error from performing index search", e);
} }
results.AddRange(fileResults);
// Intial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection. // Intial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
return results.Concat(folderResults.OrderBy(x => x.Title)).Concat(fileResults.OrderBy(x => x.Title)).ToList(); ; return results;
} }
internal async Task<List<Result>> WindowsIndexSearchAsync(string searchString, string connectionString, internal async Task<List<Result>> WindowsIndexSearchAsync(string searchString, string connectionString,

View file

@ -42,7 +42,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
// Get the ISearchQueryHelper which will help us to translate AQS --> SQL necessary to query the indexer // Get the ISearchQueryHelper which will help us to translate AQS --> SQL necessary to query the indexer
var queryHelper = catalogManager.GetQueryHelper(); var queryHelper = catalogManager.GetQueryHelper();
return queryHelper; return queryHelper;
} }
@ -81,11 +81,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
var previousLevelDirectory = path.Substring(0, indexOfSeparator); var previousLevelDirectory = path.Substring(0, indexOfSeparator);
if (string.IsNullOrEmpty(itemName)) if (string.IsNullOrEmpty(itemName))
return searchDepth + $"{previousLevelDirectory}'"; return $"{searchDepth}{previousLevelDirectory}'";
return $"(System.FileName LIKE '{itemName}%' " + return $"(System.FileName LIKE '{itemName}%' OR CONTAINS(System.FileName,'\"{itemName}*\"',1033)) AND {searchDepth}{previousLevelDirectory}'";
$"OR CONTAINS(System.FileName,'\"{itemName}*\"',1033)) AND " +
searchDepth + $"{previousLevelDirectory}'";
} }
///<summary> ///<summary>
@ -96,9 +94,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE "; string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";
if (path.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > path.LastIndexOf(Constants.DirectorySeperator)) if (path.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > path.LastIndexOf(Constants.DirectorySeperator))
return query + QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(path); return query + QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(path) + QueryOrderByFileNameRestriction;
return query + QueryWhereRestrictionsForTopLevelDirectorySearch(path); return query + QueryWhereRestrictionsForTopLevelDirectorySearch(path) + QueryOrderByFileNameRestriction;
} }
///<summary> ///<summary>
@ -107,16 +105,17 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
public string QueryForAllFilesAndFolders(string userSearchString) public string QueryForAllFilesAndFolders(string userSearchString)
{ {
// Generate SQL from constructed parameters, converting the userSearchString from AQS->WHERE clause // Generate SQL from constructed parameters, converting the userSearchString from AQS->WHERE clause
return CreateBaseQuery().GenerateSQLFromUserQuery(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch(); return CreateBaseQuery().GenerateSQLFromUserQuery(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch
+ QueryOrderByFileNameRestriction;
} }
///<summary> ///<summary>
/// Set the required WHERE clause restriction to search for all files and folders. /// Set the required WHERE clause restriction to search for all files and folders.
///</summary> ///</summary>
public string QueryWhereRestrictionsForAllFilesAndFoldersSearch() public const string QueryWhereRestrictionsForAllFilesAndFoldersSearch = "scope='file:'";
{
return $"scope='file:'"; public const string QueryOrderByFileNameRestriction = " ORDER BY System.FileName";
}
///<summary> ///<summary>
/// Search will be performed on all indexed file contents for the specified search keywords. /// Search will be performed on all indexed file contents for the specified search keywords.
@ -125,7 +124,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
{ {
string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE "; string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";
return query + QueryWhereRestrictionsForFileContentSearch(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch(); return query + QueryWhereRestrictionsForFileContentSearch(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch
+ QueryOrderByFileNameRestriction;
} }
///<summary> ///<summary>

View file

@ -1,7 +1,6 @@
using Flow.Launcher.Plugin.Explorer.Search; using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search.FolderLinks; using Flow.Launcher.Plugin.Explorer.Search.FolderLinks;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Flow.Launcher.Plugin.Explorer namespace Flow.Launcher.Plugin.Explorer
{ {

View file

@ -7,7 +7,7 @@
"Name": "Explorer", "Name": "Explorer",
"Description": "Search and manage files and folders. Explorer utilises Windows Index Search", "Description": "Search and manage files and folders. Explorer utilises Windows Index Search",
"Author": "Jeremy Wu", "Author": "Jeremy Wu",
"Version": "1.3.0", "Version": "1.4.0",
"Language": "csharp", "Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher", "Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll", "ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll",

View file

@ -41,6 +41,9 @@ namespace Flow.Launcher.Plugin.Program
public async Task<List<Result>> QueryAsync(Query query, CancellationToken token) public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
{ {
if (IsStartupIndexProgramsRequired)
_ = IndexPrograms();
Win32[] win32; Win32[] win32;
UWP.Application[] uwps; UWP.Application[] uwps;
@ -147,7 +150,7 @@ namespace Flow.Launcher.Plugin.Program
var t2 = Task.Run(IndexUwpPrograms); var t2 = Task.Run(IndexUwpPrograms);
await Task.WhenAll(t1, t2); await Task.WhenAll(t1, t2).ConfigureAwait(false);
_settings.LastIndexTime = DateTime.Today; _settings.LastIndexTime = DateTime.Today;
} }

View file

@ -51,7 +51,7 @@ namespace Flow.Launcher.Plugin.Program.Views
private void ViewRefresh() private void ViewRefresh()
{ {
if(programSourceView.Items.Count == 0 if (programSourceView.Items.Count == 0
&& btnProgramSourceStatus.Visibility == Visibility.Visible && btnProgramSourceStatus.Visibility == Visibility.Visible
&& btnEditProgramSource.Visibility == Visibility.Visible) && btnEditProgramSource.Visibility == Visibility.Visible)
{ {
@ -70,21 +70,19 @@ namespace Flow.Launcher.Plugin.Program.Views
programSourceView.Items.Refresh(); programSourceView.Items.Refresh();
} }
private void ReIndexing() private async void ReIndexing()
{ {
ViewRefresh(); ViewRefresh();
Task.Run(() =>
{ indexingPanel.Visibility = Visibility.Visible;
Dispatcher.Invoke(() => { indexingPanel.Visibility = Visibility.Visible; }); await Main.IndexPrograms();
Main.IndexPrograms(); indexingPanel.Visibility = Visibility.Hidden;
Dispatcher.Invoke(() => { indexingPanel.Visibility = Visibility.Hidden; });
});
} }
private void btnAddProgramSource_OnClick(object sender, RoutedEventArgs e) private void btnAddProgramSource_OnClick(object sender, RoutedEventArgs e)
{ {
var add = new AddProgramSource(context, _settings); var add = new AddProgramSource(context, _settings);
if(add.ShowDialog() ?? false) if (add.ShowDialog() ?? false)
{ {
ReIndexing(); ReIndexing();
} }
@ -165,14 +163,14 @@ namespace Flow.Launcher.Plugin.Program.Views
UniqueIdentifier = directory UniqueIdentifier = directory
}; };
directoriesToAdd.Add(source); directoriesToAdd.Add(source);
} }
} }
if (directoriesToAdd.Count() > 0) if (directoriesToAdd.Count() > 0)
{ {
directoriesToAdd.ForEach(x => _settings.ProgramSources.Add(x)); directoriesToAdd.ForEach(x => _settings.ProgramSources.Add(x));
directoriesToAdd.ForEach(x => ProgramSettingDisplayList.Add(x)); directoriesToAdd.ForEach(x => ProgramSettingDisplayList.Add(x));
ViewRefresh(); ViewRefresh();
ReIndexing(); ReIndexing();
@ -238,8 +236,8 @@ namespace Flow.Launcher.Plugin.Program.Views
ProgramSettingDisplayList.SetProgramSourcesStatus(selectedItems, true); ProgramSettingDisplayList.SetProgramSourcesStatus(selectedItems, true);
ProgramSettingDisplayList.RemoveDisabledFromSettings(); ProgramSettingDisplayList.RemoveDisabledFromSettings();
} }
if (selectedItems.IsReindexRequired()) if (selectedItems.IsReindexRequired())
ReIndexing(); ReIndexing();
@ -282,7 +280,7 @@ namespace Flow.Launcher.Plugin.Program.Views
var sortBy = columnBinding?.Path.Path ?? headerClicked.Column.Header as string; var sortBy = columnBinding?.Path.Path ?? headerClicked.Column.Header as string;
Sort(sortBy, direction); Sort(sortBy, direction);
_lastHeaderClicked = headerClicked; _lastHeaderClicked = headerClicked;
_lastDirection = direction; _lastDirection = direction;
} }