Merge pull request #1950 from TheBestPessimist/everything_update_runcount

Everything: update RunCount on file action
This commit is contained in:
Kevin Zhang 2023-03-15 14:09:37 -05:00 committed by GitHub
commit 83a44b1cee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 135 additions and 109 deletions

View file

@ -2,3 +2,4 @@ github
https https
ssh ssh
ubuntu ubuntu
runcount

View file

@ -233,8 +233,8 @@ namespace Flow.Launcher.Plugin
/// Open directory in an explorer configured by user via Flow's Settings. The default is Windows Explorer /// Open directory in an explorer configured by user via Flow's Settings. The default is Windows Explorer
/// </summary> /// </summary>
/// <param name="DirectoryPath">Directory Path to open</param> /// <param name="DirectoryPath">Directory Path to open</param>
/// <param name="FileName">Extra FileName Info</param> /// <param name="FileNameOrFilePath">Extra FileName Info</param>
public void OpenDirectory(string DirectoryPath, string FileName = null); public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null);
/// <summary> /// <summary>
/// Opens the URL with the given Uri object. /// Opens the URL with the given Uri object.

View file

@ -178,7 +178,7 @@ namespace Flow.Launcher.Plugin
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return Title + SubTitle; return Title + SubTitle + Score;
} }
/// <summary> /// <summary>

View file

@ -14,8 +14,6 @@ namespace Flow.Launcher.Plugin.SharedCommands
{ {
private const string FileExplorerProgramName = "explorer"; private const string FileExplorerProgramName = "explorer";
private const string FileExplorerProgramEXE = "explorer.exe";
/// <summary> /// <summary>
/// Copies the folder and all of its files and folders /// Copies the folder and all of its files and folders
/// including subfolders to the target location /// including subfolders to the target location
@ -151,7 +149,12 @@ namespace Flow.Launcher.Plugin.SharedCommands
/// <param name="fileOrFolderPath"></param> /// <param name="fileOrFolderPath"></param>
public static void OpenPath(string fileOrFolderPath) public static void OpenPath(string fileOrFolderPath)
{ {
var psi = new ProcessStartInfo { FileName = FileExplorerProgramName, UseShellExecute = true, Arguments = '"' + fileOrFolderPath + '"' }; var psi = new ProcessStartInfo
{
FileName = FileExplorerProgramName,
UseShellExecute = true,
Arguments = '"' + fileOrFolderPath + '"'
};
try try
{ {
if (LocationExists(fileOrFolderPath) || FileExists(fileOrFolderPath)) if (LocationExists(fileOrFolderPath) || FileExists(fileOrFolderPath))
@ -167,15 +170,6 @@ namespace Flow.Launcher.Plugin.SharedCommands
} }
} }
/// <summary>
/// Open the folder that contains <paramref name="path"/>
/// </summary>
/// <param name="path"></param>
public static void OpenContainingFolder(string path)
{
Process.Start(FileExplorerProgramEXE, $" /select,\"{path}\"");
}
///<summary> ///<summary>
/// This checks whether a given string is a directory path or network location string. /// This checks whether a given string is a directory path or network location string.
/// It does not check if location actually exists. /// It does not check if location actually exists.

View file

@ -1,4 +1,4 @@
 using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
@ -195,17 +195,20 @@ namespace Flow.Launcher
((PluginJsonStorage<T>)_pluginJsonStorages[type]).Save(); ((PluginJsonStorage<T>)_pluginJsonStorages[type]).Save();
} }
public void OpenDirectory(string DirectoryPath, string FileName = null) public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null)
{ {
using var explorer = new Process(); using var explorer = new Process();
var explorerInfo = _settingsVM.Settings.CustomExplorer; var explorerInfo = _settingsVM.Settings.CustomExplorer;
explorer.StartInfo = new ProcessStartInfo explorer.StartInfo = new ProcessStartInfo
{ {
FileName = explorerInfo.Path, FileName = explorerInfo.Path,
Arguments = FileName is null ? Arguments = FileNameOrFilePath is null
explorerInfo.DirectoryArgument.Replace("%d", DirectoryPath) : ? explorerInfo.DirectoryArgument.Replace("%d", DirectoryPath)
explorerInfo.FileArgument.Replace("%d", DirectoryPath).Replace("%f", : explorerInfo.FileArgument
Path.IsPathRooted(FileName) ? FileName : Path.Combine(DirectoryPath, FileName)) .Replace("%d", DirectoryPath)
.Replace("%f",
Path.IsPathRooted(FileNameOrFilePath) ? FileNameOrFilePath : Path.Combine(DirectoryPath, FileNameOrFilePath)
)
}; };
explorer.Start(); explorer.Start();
} }

View file

@ -17,7 +17,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
{ {
private const int BufferSize = 4096; private const int BufferSize = 4096;
private static SemaphoreSlim _semaphore = new(1, 1); private static readonly SemaphoreSlim _semaphore = new(1, 1);
// cached buffer to remove redundant allocations. // cached buffer to remove redundant allocations.
private static readonly StringBuilder buffer = new(BufferSize); private static readonly StringBuilder buffer = new(BufferSize);
@ -34,6 +34,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
InvalidCallError InvalidCallError
} }
const uint EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME = 0x00000004u;
const uint EVERYTHING_REQUEST_RUN_COUNT = 0x00000400u;
/// <summary> /// <summary>
/// Checks whether the sort option is Fast Sort. /// Checks whether the sort option is Fast Sort.
/// </summary> /// </summary>
@ -113,6 +116,17 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
EverythingApiDllImport.Everything_SetSort(option.SortOption); EverythingApiDllImport.Everything_SetSort(option.SortOption);
EverythingApiDllImport.Everything_SetMatchPath(option.IsFullPathSearch); EverythingApiDllImport.Everything_SetMatchPath(option.IsFullPathSearch);
if (option.SortOption == SortOption.RUN_COUNT_DESCENDING)
{
EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME | EVERYTHING_REQUEST_RUN_COUNT);
}
else
{
EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME);
}
if (token.IsCancellationRequested) yield break; if (token.IsCancellationRequested) yield break;
if (!EverythingApiDllImport.Everything_QueryW(true)) if (!EverythingApiDllImport.Everything_QueryW(true))
@ -132,10 +146,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
var result = new SearchResult var result = new SearchResult
{ {
// todo the types are wrong. Everything expects uint everywhere, but we send int just above/below. how to fix? Is EverythingApiDllImport autogenerated or handmade?
FullPath = buffer.ToString(), FullPath = buffer.ToString(),
Type = EverythingApiDllImport.Everything_IsFolderResult(idx) ? ResultType.Folder : Type = EverythingApiDllImport.Everything_IsFolderResult(idx) ? ResultType.Folder :
EverythingApiDllImport.Everything_IsFileResult(idx) ? ResultType.File : EverythingApiDllImport.Everything_IsFileResult(idx) ? ResultType.File :
ResultType.Volume ResultType.Volume,
Score = (int)EverythingApiDllImport.Everything_GetResultRunCount( (uint)idx)
}; };
yield return result; yield return result;
@ -172,5 +188,19 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
} }
public static async Task IncrementRunCounterAsync(string fileOrFolder)
{
await _semaphore.WaitAsync(TimeSpan.FromSeconds(1));
try
{
_ = EverythingApiDllImport.Everything_IncRunCountFromFileName(fileOrFolder);
}
catch (Exception)
{
/*ignored*/
}
finally { _semaphore.Release(); }
}
} }
} }

View file

@ -39,6 +39,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
Main.Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue")); Main.Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue"));
} }
} }
private async ValueTask<bool> ClickToInstallEverythingAsync(ActionContext _) private async ValueTask<bool> ClickToInstallEverythingAsync(ActionContext _)
{ {
var installedPath = await EverythingDownloadHelper.PromptDownloadIfNotInstallAsync(Settings.EverythingInstalledPath, Main.Context.API); var installedPath = await EverythingDownloadHelper.PromptDownloadIfNotInstallAsync(Settings.EverythingInstalledPath, Main.Context.API);
@ -68,8 +69,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
await foreach (var result in EverythingApi.SearchAsync(option, token)) await foreach (var result in EverythingApi.SearchAsync(option, token))
yield return result; yield return result;
} }
public async IAsyncEnumerable<SearchResult> ContentSearchAsync(string plainSearch,
string contentSearch, public async IAsyncEnumerable<SearchResult> ContentSearchAsync(string plainSearch, string contentSearch,
[EnumeratorCancellation] CancellationToken token) [EnumeratorCancellation] CancellationToken token)
{ {
await ThrowIfEverythingNotAvailableAsync(token); await ThrowIfEverythingNotAvailableAsync(token);
@ -102,6 +103,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
yield return result; yield return result;
} }
} }
public async IAsyncEnumerable<SearchResult> EnumerateAsync(string path, string search, bool recursive, [EnumeratorCancellation] CancellationToken token) public async IAsyncEnumerable<SearchResult> EnumerateAsync(string path, string search, bool recursive, [EnumeratorCancellation] CancellationToken token)
{ {
await ThrowIfEverythingNotAvailableAsync(token); await ThrowIfEverythingNotAvailableAsync(token);

View file

@ -27,7 +27,6 @@ namespace Flow.Launcher.Plugin.Everything.Everything
ATTRIBUTES_DESCENDING = 16u, ATTRIBUTES_DESCENDING = 16u,
FILE_LIST_FILENAME_ASCENDING = 17u, FILE_LIST_FILENAME_ASCENDING = 17u,
FILE_LIST_FILENAME_DESCENDING = 18u, FILE_LIST_FILENAME_DESCENDING = 18u,
RUN_COUNT_ASCENDING = 19u,
RUN_COUNT_DESCENDING = 20u, RUN_COUNT_DESCENDING = 20u,
DATE_RECENTLY_CHANGED_ASCENDING = 21u, DATE_RECENTLY_CHANGED_ASCENDING = 21u,
DATE_RECENTLY_CHANGED_DESCENDING = 22u, DATE_RECENTLY_CHANGED_DESCENDING = 22u,

View file

@ -7,6 +7,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using Flow.Launcher.Plugin.Explorer.Search.Everything;
namespace Flow.Launcher.Plugin.Explorer.Search namespace Flow.Launcher.Plugin.Explorer.Search
{ {
@ -37,13 +38,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search
var keyword = usePathSearchActionKeyword ? pathSearchActionKeyword : searchActionKeyword; var keyword = usePathSearchActionKeyword ? pathSearchActionKeyword : searchActionKeyword;
var formatted_path = path; var formattedPath = path;
if (type == ResultType.Folder) if (type == ResultType.Folder)
// the separator is needed so when navigating the folder structure contents of the folder are listed // the separator is needed so when navigating the folder structure contents of the folder are listed
formatted_path = path.EndsWith(Constants.DirectorySeparator) ? path : path + Constants.DirectorySeparator; formattedPath = path.EndsWith(Constants.DirectorySeparator) ? path : path + Constants.DirectorySeparator;
return $"{keyword}{formatted_path}"; return $"{keyword}{formattedPath}";
} }
public static string GetAutoCompleteText(string title, Query query, string path, ResultType resultType) public static string GetAutoCompleteText(string title, Query query, string path, ResultType resultType)
@ -57,10 +58,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{ {
return result.Type switch return result.Type switch
{ {
ResultType.Folder or ResultType.Volume => CreateFolderResult(Path.GetFileName(result.FullPath), ResultType.Folder or ResultType.Volume =>
result.FullPath, result.FullPath, query, 0, result.WindowsIndexed), CreateFolderResult(Path.GetFileName(result.FullPath), result.FullPath, result.FullPath, query, result.Score, result.WindowsIndexed),
ResultType.File => CreateFileResult( ResultType.File =>
result.FullPath, query, 0, result.WindowsIndexed), CreateFileResult(result.FullPath, query, result.Score, result.WindowsIndexed),
_ => throw new ArgumentOutOfRangeException() _ => throw new ArgumentOutOfRangeException()
}; };
} }
@ -77,11 +78,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search
CopyText = path, CopyText = path,
Action = c => Action = c =>
{ {
// open folder
if (c.SpecialKeyState.CtrlPressed || (!Settings.PathSearchKeywordEnabled && !Settings.SearchActionKeywordEnabled)) if (c.SpecialKeyState.CtrlPressed || (!Settings.PathSearchKeywordEnabled && !Settings.SearchActionKeywordEnabled))
{ {
try try
{ {
Context.API.OpenDirectory(path); OpenFolder(path);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
@ -91,6 +93,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
} }
} }
// or make this folder the current query
Context.API.ChangeQuery(GetPathWithActionKeyword(path, ResultType.Folder, query.ActionKeyword)); Context.API.ChangeQuery(GetPathWithActionKeyword(path, ResultType.Folder, query.ActionKeyword));
return false; return false;
@ -98,12 +101,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
Score = score, Score = score,
TitleToolTip = InternationalizationManager.Instance.GetTranslation("plugin_explorer_plugin_ToolTipOpenDirectory"), TitleToolTip = InternationalizationManager.Instance.GetTranslation("plugin_explorer_plugin_ToolTipOpenDirectory"),
SubTitleToolTip = path, SubTitleToolTip = path,
ContextData = new SearchResult ContextData = new SearchResult { Type = ResultType.Folder, FullPath = path, WindowsIndexed = windowsIndexed }
{
Type = ResultType.Folder,
FullPath = path,
WindowsIndexed = windowsIndexed
}
}; };
} }
@ -112,7 +110,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search
var progressBarColor = "#26a0da"; var progressBarColor = "#26a0da";
var title = string.Empty; // hide title when use progress bar, var title = string.Empty; // hide title when use progress bar,
var driveLetter = path[..1].ToUpper(); var driveLetter = path[..1].ToUpper();
var driveName = driveLetter + ":\\";
DriveInfo drv = new DriveInfo(driveLetter); DriveInfo drv = new DriveInfo(driveLetter);
var freespace = ToReadableSize(drv.AvailableFreeSpace, 2); var freespace = ToReadableSize(drv.AvailableFreeSpace, 2);
var totalspace = ToReadableSize(drv.TotalSize, 2); var totalspace = ToReadableSize(drv.TotalSize, 2);
@ -133,19 +130,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search
Score = 500, Score = 500,
ProgressBar = progressValue, ProgressBar = progressValue,
ProgressBarColor = progressBarColor, ProgressBarColor = progressBarColor,
Action = c => Action = _ =>
{ {
Context.API.OpenDirectory(path); OpenFolder(path);
return true; return true;
}, },
TitleToolTip = path, TitleToolTip = path,
SubTitleToolTip = path, SubTitleToolTip = path,
ContextData = new SearchResult ContextData = new SearchResult { Type = ResultType.Volume, FullPath = path, WindowsIndexed = windowsIndexed }
{
Type = ResultType.Volume,
FullPath = path,
WindowsIndexed = windowsIndexed
}
}; };
} }
@ -153,7 +145,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{ {
int mok = 0; int mok = 0;
double drvSize = pDrvSize; double drvSize = pDrvSize;
string Space = "Byte"; string uom = "Byte"; // Unit Of Measurement
while (drvSize > 1024.0) while (drvSize > 1024.0)
{ {
@ -162,23 +154,23 @@ namespace Flow.Launcher.Plugin.Explorer.Search
} }
if (mok == 1) if (mok == 1)
Space = "KB"; uom = "KB";
else if (mok == 2) else if (mok == 2)
Space = " MB"; uom = " MB";
else if (mok == 3) else if (mok == 3)
Space = " GB"; uom = " GB";
else if (mok == 4) else if (mok == 4)
Space = " TB"; uom = " TB";
var returnStr = $"{Convert.ToInt32(drvSize)}{Space}"; var returnStr = $"{Convert.ToInt32(drvSize)}{uom}";
if (mok != 0) if (mok != 0)
{ {
returnStr = pi switch returnStr = pi switch
{ {
1 => $"{drvSize:F1}{Space}", 1 => $"{drvSize:F1}{uom}",
2 => $"{drvSize:F2}{Space}", 2 => $"{drvSize:F2}{uom}",
3 => $"{drvSize:F3}{Space}", 3 => $"{drvSize:F3}{uom}",
_ => $"{Convert.ToInt32(drvSize)}{Space}" _ => $"{Convert.ToInt32(drvSize)}{uom}"
}; };
} }
@ -201,24 +193,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search
CopyText = folderPath, CopyText = folderPath,
Action = _ => Action = _ =>
{ {
Context.API.OpenDirectory(folderPath); OpenFolder(folderPath);
return true; return true;
}, },
ContextData = new SearchResult ContextData = new SearchResult { Type = ResultType.Folder, FullPath = folderPath, WindowsIndexed = windowsIndexed }
{
Type = ResultType.Folder,
FullPath = folderPath,
WindowsIndexed = windowsIndexed
}
}; };
} }
internal static Result CreateFileResult(string filePath, Query query, int score = 0, bool windowsIndexed = false) internal static Result CreateFileResult(string filePath, Query query, int score = 0, bool windowsIndexed = false)
{ {
Result.PreviewInfo preview = IsMedia(Path.GetExtension(filePath)) ? new Result.PreviewInfo Result.PreviewInfo preview = IsMedia(Path.GetExtension(filePath))
{ ? new Result.PreviewInfo { IsMedia = true, PreviewImagePath = filePath, }
IsMedia = true, PreviewImagePath = filePath, : Result.PreviewInfo.Default;
} : Result.PreviewInfo.Default;
var title = Path.GetFileName(filePath); var title = Path.GetFileName(filePath);
@ -236,33 +222,17 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{ {
try try
{ {
if (File.Exists(filePath) && c.SpecialKeyState.CtrlPressed && c.SpecialKeyState.ShiftPressed) if (c.SpecialKeyState.CtrlPressed && c.SpecialKeyState.ShiftPressed)
{ {
_ = Task.Run(() => OpenFileAsAdmin(filePath);
{
try
{
Process.Start(new ProcessStartInfo
{
FileName = filePath,
UseShellExecute = true,
WorkingDirectory = Settings.UseLocationAsWorkingDir ? Path.GetDirectoryName(filePath) : string.Empty,
Verb = "runas",
});
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Could not start " + filePath);
}
});
} }
else if (c.SpecialKeyState.CtrlPressed) else if (c.SpecialKeyState.CtrlPressed)
{ {
Context.API.OpenDirectory(Path.GetDirectoryName(filePath), filePath); OpenFolder(filePath, filePath);
} }
else else
{ {
FilesFolders.OpenPath(filePath); OpenFile(filePath);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -274,32 +244,59 @@ namespace Flow.Launcher.Plugin.Explorer.Search
}, },
TitleToolTip = InternationalizationManager.Instance.GetTranslation("plugin_explorer_plugin_ToolTipOpenContainingFolder"), TitleToolTip = InternationalizationManager.Instance.GetTranslation("plugin_explorer_plugin_ToolTipOpenContainingFolder"),
SubTitleToolTip = filePath, SubTitleToolTip = filePath,
ContextData = new SearchResult ContextData = new SearchResult { Type = ResultType.File, FullPath = filePath, WindowsIndexed = windowsIndexed }
{
Type = ResultType.File,
FullPath = filePath,
WindowsIndexed = windowsIndexed
}
}; };
return result; return result;
} }
public static bool IsMedia(string extension) private static bool IsMedia(string extension)
{ {
if (string.IsNullOrEmpty(extension)) if (string.IsNullOrEmpty(extension)) { return false; }
{
return false; return MediaExtensions.Contains(extension.ToLowerInvariant());
}
else
{
return MediaExtensions.Contains(extension.ToLowerInvariant());
}
} }
public static readonly string[] MediaExtensions = private static void OpenFile(string filePath)
{ {
".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4" IncrementEverythingRunCounterIfNeeded(filePath);
}; FilesFolders.OpenPath(filePath);
}
private static void OpenFolder(string folderPath, string fileNameOrFilePath = null)
{
IncrementEverythingRunCounterIfNeeded(folderPath);
Context.API.OpenDirectory(Path.GetDirectoryName(folderPath), fileNameOrFilePath);
}
private static void OpenFileAsAdmin(string filePath)
{
_ = Task.Run(() =>
{
try
{
IncrementEverythingRunCounterIfNeeded(filePath);
Process.Start(new ProcessStartInfo
{
FileName = filePath,
UseShellExecute = true,
WorkingDirectory = Settings.UseLocationAsWorkingDir ? Path.GetDirectoryName(filePath) : string.Empty,
Verb = "runas",
});
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Could not start " + filePath);
}
});
}
private static void IncrementEverythingRunCounterIfNeeded(string fileOrFolder)
{
if (Settings.EverythingEnabled)
_ = Task.Run(() => EverythingApi.IncrementRunCounterAsync(fileOrFolder));
}
private static readonly string[] MediaExtensions = { ".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4" };
} }
public enum ResultType public enum ResultType