Skip to content

Commit 1eafbd1

Browse files
authored
Merge pull request #46 from Flow-Launcher/explorer_plugin
Add Explorer plugin
2 parents 06d6399 + fada494 commit 1eafbd1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2031
-998
lines changed

Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,81 @@ public static void OpenPath(string fileOrFolderPath)
127127
#endif
128128
}
129129
}
130+
131+
///<summary>
132+
/// This checks whether a given string is a directory path or network location string.
133+
/// It does not check if location actually exists.
134+
///</summary>
135+
public static bool IsLocationPathString(string querySearchString)
136+
{
137+
if (string.IsNullOrEmpty(querySearchString))
138+
return false;
139+
140+
// // shared folder location, and not \\\location\
141+
if (querySearchString.Length >= 3
142+
&& querySearchString.StartsWith(@"\\")
143+
&& char.IsLetter(querySearchString[2]))
144+
return true;
145+
146+
// c:\
147+
if (querySearchString.Length == 3
148+
&& char.IsLetter(querySearchString[0])
149+
&& querySearchString[1] == ':'
150+
&& querySearchString[2] == '\\')
151+
return true;
152+
153+
// c:\\
154+
if (querySearchString.Length >= 4
155+
&& char.IsLetter(querySearchString[0])
156+
&& querySearchString[1] == ':'
157+
&& querySearchString[2] == '\\'
158+
&& char.IsLetter(querySearchString[3]))
159+
return true;
160+
161+
return false;
162+
}
163+
164+
///<summary>
165+
/// Gets the previous level directory from a path string.
166+
/// Checks that previous level directory exists and returns it
167+
/// as a path string, or empty string if doesn't exit
168+
///</summary>
169+
public static string GetPreviousExistingDirectory(Func<string, bool> locationExists, string path)
170+
{
171+
var previousDirectoryPath = "";
172+
var index = path.LastIndexOf('\\');
173+
if (index > 0 && index < (path.Length - 1))
174+
{
175+
previousDirectoryPath = path.Substring(0, index + 1);
176+
if (!locationExists(previousDirectoryPath))
177+
{
178+
return "";
179+
}
180+
}
181+
else
182+
{
183+
return "";
184+
}
185+
186+
return previousDirectoryPath;
187+
}
188+
189+
///<summary>
190+
/// Returns the previous level directory if path incomplete (does not end with '\').
191+
/// Does not check if previous level directory exists.
192+
/// Returns passed in string if is complete path
193+
///</summary>
194+
public static string ReturnPreviousDirectoryIfIncompleteString(string path)
195+
{
196+
if (!path.EndsWith("\\"))
197+
{
198+
// not full path, get previous level directory string
199+
var indexOfSeparator = path.LastIndexOf('\\');
200+
201+
return path.Substring(0, indexOfSeparator + 1);
202+
}
203+
204+
return path;
205+
}
130206
}
131207
}

Flow.Launcher.Test/Flow.Launcher.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
</ItemGroup>
4040

4141
<ItemGroup>
42+
<ProjectReference Include="..\Plugins\Flow.Launcher.Plugin.Explorer\Flow.Launcher.Plugin.Explorer.csproj" />
4243
<ProjectReference Include="..\Plugins\Flow.Launcher.Plugin.Program\Flow.Launcher.Plugin.Program.csproj" />
4344
<ProjectReference Include="..\Plugins\Flow.Launcher.Plugin.Url\Flow.Launcher.Plugin.Url.csproj" />
4445
<ProjectReference Include="..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
using Flow.Launcher.Plugin;
2+
using Flow.Launcher.Plugin.Explorer;
3+
using Flow.Launcher.Plugin.Explorer.Search;
4+
using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo;
5+
using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
6+
using Flow.Launcher.Plugin.SharedCommands;
7+
using NUnit.Framework;
8+
using System;
9+
using System.Collections.Generic;
10+
11+
namespace Flow.Launcher.Test.Plugins
12+
{
13+
/// <summary>
14+
/// These tests require the use of CSearchManager class from Microsoft.Search.Interop.
15+
/// Windows Search service needs to be running to complete the tests
16+
/// </summary>
17+
[TestFixture]
18+
public class ExplorerTest
19+
{
20+
private List<Result> MethodWindowsIndexSearchReturnsZeroResults(Query dummyQuery, string dummyString)
21+
{
22+
return new List<Result>();
23+
}
24+
25+
private List<Result> MethodDirectoryInfoClassSearchReturnsTwoResults(Query dummyQuery, string dummyString)
26+
{
27+
return new List<Result>
28+
{
29+
new Result
30+
{
31+
Title="Result 1"
32+
},
33+
34+
new Result
35+
{
36+
Title="Result 2"
37+
}
38+
};
39+
}
40+
41+
private bool PreviousLocationExistsReturnsTrue(string dummyString) => true;
42+
43+
private bool PreviousLocationNotExistReturnsFalse(string dummyString) => false;
44+
45+
[TestCase("C:\\SomeFolder\\", "directory='file:C:\\SomeFolder\\'")]
46+
public void GivenWindowsIndexSearch_WhenProvidedFolderPath_ThenQueryWhereRestrictionsShouldUseDirectoryString(string path, string expectedString)
47+
{
48+
// Given
49+
var queryConstructor = new QueryConstructor(new Settings());
50+
51+
// When
52+
var folderPath = path;
53+
var result = queryConstructor.QueryWhereRestrictionsForTopLevelDirectorySearch(folderPath);
54+
55+
// Then
56+
Assert.IsTrue(result == expectedString,
57+
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
58+
$"Actual: {result}{Environment.NewLine}");
59+
}
60+
61+
[TestCase("C:\\", "SELECT TOP 100 System.FileName, System.ItemPathDisplay, System.ItemType FROM SystemIndex WHERE directory='file:C:\\'")]
62+
[TestCase("C:\\SomeFolder\\", "SELECT TOP 100 System.FileName, System.ItemPathDisplay, System.ItemType FROM SystemIndex WHERE directory='file:C:\\SomeFolder\\'")]
63+
public void GivenWindowsIndexSearch_WhenSearchTypeIsTopLevelDirectorySearch_ThenQueryShouldUseExpectedString(string folderPath, string expectedString)
64+
{
65+
// Given
66+
var queryConstructor = new QueryConstructor(new Settings());
67+
68+
//When
69+
var queryString = queryConstructor.QueryForTopLevelDirectorySearch(folderPath);
70+
71+
// Then
72+
Assert.IsTrue(queryString == expectedString,
73+
$"Expected string: {expectedString}{Environment.NewLine} " +
74+
$"Actual string was: {queryString}{Environment.NewLine}");
75+
}
76+
77+
[TestCase("C:\\SomeFolder\\flow.launcher.sln", "SELECT TOP 100 System.FileName, System.ItemPathDisplay, System.ItemType " +
78+
"FROM SystemIndex WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
79+
"OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033))" +
80+
" AND directory='file:C:\\SomeFolder'")]
81+
public void GivenWindowsIndexSearchTopLevelDirectory_WhenSearchingForSpecificItem_ThenQueryShouldUseExpectedString(
82+
string userSearchString, string expectedString)
83+
{
84+
// Given
85+
var queryConstructor = new QueryConstructor(new Settings());
86+
87+
//When
88+
var queryString = queryConstructor.QueryForTopLevelDirectorySearch(userSearchString);
89+
90+
// Then
91+
Assert.IsTrue(queryString == expectedString,
92+
$"Expected string: {expectedString}{Environment.NewLine} " +
93+
$"Actual string was: {queryString}{Environment.NewLine}");
94+
}
95+
96+
[TestCase("C:\\SomeFolder\\SomeApp", "(System.FileName LIKE 'SomeApp%' " +
97+
"OR CONTAINS(System.FileName,'\"SomeApp*\"',1033))" +
98+
" AND directory='file:C:\\SomeFolder'")]
99+
public void GivenWindowsIndexSearchTopLevelDirectory_WhenSearchingForSpecificItem_ThenQueryWhereRestrictionsShouldUseDirectoryString(
100+
string userSearchString, string expectedString)
101+
{
102+
// Given
103+
var queryConstructor = new QueryConstructor(new Settings());
104+
105+
//When
106+
var queryString = queryConstructor.QueryWhereRestrictionsForTopLevelDirectorySearch(userSearchString);
107+
108+
// Then
109+
Assert.IsTrue(queryString == expectedString,
110+
$"Expected string: {expectedString}{Environment.NewLine} " +
111+
$"Actual string was: {queryString}{Environment.NewLine}");
112+
}
113+
114+
[TestCase("scope='file:'")]
115+
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryWhereRestrictionsShouldUseScopeString(string expectedString)
116+
{
117+
// Given
118+
var queryConstructor = new QueryConstructor(new Settings());
119+
120+
//When
121+
var resultString = queryConstructor.QueryWhereRestrictionsForAllFilesAndFoldersSearch();
122+
123+
// Then
124+
Assert.IsTrue(resultString == expectedString,
125+
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
126+
$"Actual string was: {resultString}{Environment.NewLine}");
127+
}
128+
129+
[TestCase("flow.launcher.sln", "SELECT TOP 100 \"System.FileName\", \"System.ItemPathDisplay\", \"System.ItemType\" " +
130+
"FROM \"SystemIndex\" WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
131+
"OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033)) AND scope='file:'")]
132+
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryShouldUseExpectedString(
133+
string userSearchString, string expectedString)
134+
{
135+
// Given
136+
var queryConstructor = new QueryConstructor(new Settings());
137+
138+
//When
139+
var resultString = queryConstructor.QueryForAllFilesAndFolders(userSearchString);
140+
141+
// Then
142+
Assert.IsTrue(resultString == expectedString,
143+
$"Expected query string: {expectedString}{Environment.NewLine} " +
144+
$"Actual string was: {resultString}{Environment.NewLine}");
145+
}
146+
147+
[TestCase]
148+
public void GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMethodShouldContinueDirectoryInfoClassSearch()
149+
{
150+
// Given
151+
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
152+
153+
// When
154+
var results = searchManager.TopLevelDirectorySearchBehaviour(
155+
MethodWindowsIndexSearchReturnsZeroResults,
156+
MethodDirectoryInfoClassSearchReturnsTwoResults,
157+
false,
158+
new Query(),
159+
"string not used");
160+
161+
// Then
162+
Assert.IsTrue(results.Count == 2,
163+
$"Expected to have 2 results from DirectoryInfoClassSearch {Environment.NewLine} " +
164+
$"Actual number of results is {results.Count} {Environment.NewLine}");
165+
}
166+
167+
[TestCase]
168+
public void GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMethodShouldNotContinueDirectoryInfoClassSearch()
169+
{
170+
// Given
171+
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
172+
173+
// When
174+
var results = searchManager.TopLevelDirectorySearchBehaviour(
175+
MethodWindowsIndexSearchReturnsZeroResults,
176+
MethodDirectoryInfoClassSearchReturnsTwoResults,
177+
true,
178+
new Query(),
179+
"string not used");
180+
181+
// Then
182+
Assert.IsTrue(results.Count == 0,
183+
$"Expected to have 0 results because location is indexed {Environment.NewLine} " +
184+
$"Actual number of results is {results.Count} {Environment.NewLine}");
185+
}
186+
187+
[TestCase(@"c:\\", false)]
188+
[TestCase(@"i:\", true)]
189+
[TestCase(@"\c:\", false)]
190+
[TestCase(@"cc:\", false)]
191+
[TestCase(@"\\\SomeNetworkLocation\", false)]
192+
[TestCase("RandomFile", false)]
193+
public void WhenGivenQuerySearchString_ThenShouldIndicateIfIsLocationPathString(string querySearchString, bool expectedResult)
194+
{
195+
// When, Given
196+
var result = FilesFolders.IsLocationPathString(querySearchString);
197+
198+
//Then
199+
Assert.IsTrue(result == expectedResult,
200+
$"Expected query search string check result is: {expectedResult} {Environment.NewLine} " +
201+
$"Actual check result is {result} {Environment.NewLine}");
202+
203+
}
204+
205+
[TestCase(@"C:\SomeFolder\SomeApp", true, @"C:\SomeFolder\")]
206+
[TestCase(@"C:\SomeFolder\SomeApp\SomeFile", true, @"C:\SomeFolder\SomeApp\")]
207+
[TestCase(@"C:\NonExistentFolder\SomeApp", false, "")]
208+
public void GivenAPartialPath_WhenPreviousLevelDirectoryExists_ThenShouldReturnThePreviousDirectoryPathString(
209+
string path, bool previousDirectoryExists, string expectedString)
210+
{
211+
// When
212+
Func<string, bool> previousLocationExists = null;
213+
if (previousDirectoryExists)
214+
{
215+
previousLocationExists = PreviousLocationExistsReturnsTrue;
216+
}
217+
else
218+
{
219+
previousLocationExists = PreviousLocationNotExistReturnsFalse;
220+
}
221+
222+
// Given
223+
var previousDirectoryPath = FilesFolders.GetPreviousExistingDirectory(previousLocationExists, path);
224+
225+
//Then
226+
Assert.IsTrue(previousDirectoryPath == expectedString,
227+
$"Expected path string: {expectedString} {Environment.NewLine} " +
228+
$"Actual path string is {previousDirectoryPath} {Environment.NewLine}");
229+
}
230+
231+
[TestCase(@"C:\NonExistentFolder\SomeApp", @"C:\NonExistentFolder\")]
232+
[TestCase(@"C:\NonExistentFolder\SomeApp\", @"C:\NonExistentFolder\SomeApp\")]
233+
public void WhenGivenAPath_ThenShouldReturnThePreviousDirectoryPathIfIncompleteOrOriginalString(
234+
string path, string expectedString)
235+
{
236+
var returnedPath = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(path);
237+
238+
//Then
239+
Assert.IsTrue(returnedPath == expectedString,
240+
$"Expected path string: {expectedString} {Environment.NewLine} " +
241+
$"Actual path string is {returnedPath} {Environment.NewLine}");
242+
}
243+
244+
[TestCase("c:\\SomeFolder\\>", "scope='file:c:\\SomeFolder'")]
245+
[TestCase("c:\\SomeFolder\\>SomeName", "(System.FileName LIKE 'SomeName%' " +
246+
"OR CONTAINS(System.FileName,'\"SomeName*\"',1033)) AND " +
247+
"scope='file:c:\\SomeFolder'")]
248+
public void GivenWindowsIndexSearch_WhenSearchPatternHotKeyIsSearchAll_ThenQueryWhereRestrictionsShouldUseScopeString(string path, string expectedString)
249+
{
250+
// Given
251+
var queryConstructor = new QueryConstructor(new Settings());
252+
253+
//When
254+
var resultString = queryConstructor.QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(path);
255+
256+
// Then
257+
Assert.IsTrue(resultString == expectedString,
258+
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
259+
$"Actual string was: {resultString}{Environment.NewLine}");
260+
}
261+
262+
[TestCase("c:\\somefolder\\>somefile","*somefile*")]
263+
[TestCase("c:\\somefolder\\somefile", "somefile*")]
264+
[TestCase("c:\\somefolder\\", "*")]
265+
public void GivenDirectoryInfoSearch_WhenSearchPatternHotKeyIsSearchAll_ThenSearchCriteriaShouldUseCriteriaString(string path, string expectedString)
266+
{
267+
// Given
268+
var criteriaConstructor = new DirectoryInfoSearch(new PluginInitContext());
269+
270+
//When
271+
var resultString = criteriaConstructor.ConstructSearchCriteria(path);
272+
273+
// Then
274+
Assert.IsTrue(resultString == expectedString,
275+
$"Expected criteria string: {expectedString}{Environment.NewLine} " +
276+
$"Actual criteria string was: {resultString}{Environment.NewLine}");
277+
}
278+
}
279+
}

0 commit comments

Comments
 (0)