Skip to content

Commit 441604b

Browse files
authored
Fix: Fixed an issue where shortcuts weren't displayed in search results (#18628)
1 parent ce6648a commit 441604b

4 files changed

Lines changed: 188 additions & 8 deletions

File tree

src/Files.App/Data/Models/SuggestionModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public sealed partial class SuggestionModel : ObservableObject, IOmnibarTextMemb
1212
{
1313
public bool IsRecentSearch { get; set; } = false;
1414

15+
public bool IsShortcut { get; set; } = false;
16+
1517
public bool LoadFileIcon { get; set; } = false;
1618

1719
public bool NeedsPlaceholderGlyph { get; set; } = true;
@@ -73,6 +75,7 @@ private void Img_ImageOpened(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
7375

7476
public SuggestionModel(ListedItem item)
7577
{
78+
IsShortcut = item.IsShortcut;
7679
LoadFileIcon = item.LoadFileIcon;
7780
NeedsPlaceholderGlyph = item.NeedsPlaceholderGlyph;
7881
ItemPath = item.ItemPath;

src/Files.App/UserControls/NavigationToolbar.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,15 @@
374374
x:Load="{x:Bind NeedsPlaceholderGlyph, Mode=OneWay}"
375375
FontSize="14"
376376
Glyph="{x:Bind IsRecentSearch, Mode=OneTime, Converter={StaticResource SearchSuggestionGlyphConverter}}" />
377+
<Viewbox
378+
x:Name="ShortcutGlyphElement"
379+
Width="10"
380+
Height="10"
381+
HorizontalAlignment="Left"
382+
VerticalAlignment="Bottom"
383+
x:Load="{x:Bind IsShortcut}">
384+
<controls:ThemedIcon Style="{StaticResource App.ThemedIcons.Shortcut}" />
385+
</Viewbox>
377386
</Grid>
378387
<StackPanel Grid.Column="1" VerticalAlignment="Center">
379388
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />

src/Files.App/Utils/Storage/Search/FolderSearch.cs

Lines changed: 175 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Files Community
22
// Licensed under the MIT License.
33

4+
using Files.Shared.Helpers;
45
using Microsoft.Extensions.Logging;
56
using System.IO;
67
using System.Text.RegularExpressions;
@@ -66,7 +67,8 @@ public string AQSQuery
6667
}
6768
else
6869
{
69-
return $"System.FileName:\"{QueryWithWildcard}\"";
70+
var escaped = QueryWithWildcard.Replace("\"", "\\\"");
71+
return QueryWithWildcard.Contains(' ') ? $"System.FileName:\"{escaped}\"" : $"System.FileName:{QueryWithWildcard}";
7072
}
7173
}
7274
}
@@ -377,7 +379,7 @@ private async Task AddItemsAsync(string folder, IList<ListedItem> results, Cance
377379
hiddenOnlyFromWin32 = (results.Count != 0);
378380
}
379381

380-
if (!IsAQSQuery && (!hiddenOnlyFromWin32 || UserSettingsService.FoldersSettingsService.ShowHiddenItems))
382+
if (!IsAQSQuery)
381383
{
382384
await SearchWithWin32Async(folder, hiddenOnlyFromWin32, UsedMaxItemCount - (uint)results.Count, results, token);
383385
}
@@ -390,11 +392,13 @@ private async Task SearchWithWin32Async(string folder, bool hiddenOnly, uint max
390392
(IntPtr hFile, WIN32_FIND_DATA findData) = await Task.Run(() =>
391393
{
392394
int additionalFlags = Win32PInvoke.FIND_FIRST_EX_LARGE_FETCH;
393-
IntPtr hFileTsk = Win32PInvoke.FindFirstFileExFromApp($"{folder}\\{QueryWithWildcard}", Win32PInvoke.FINDEX_INFO_LEVELS.FindExInfoBasic,
395+
IntPtr hFileTsk = Win32PInvoke.FindFirstFileExFromApp($"{folder}\\*{QueryWithWildcard}", Win32PInvoke.FINDEX_INFO_LEVELS.FindExInfoBasic,
394396
out WIN32_FIND_DATA findDataTsk, Win32PInvoke.FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags);
395397
return (hFileTsk, findDataTsk);
396398
}).WithTimeoutAsync(TimeSpan.FromSeconds(5));
397399

400+
var pendingShortcuts = new List<(string Path, WIN32_FIND_DATA FindData)>();
401+
398402
if (hFile != IntPtr.Zero && hFile.ToInt64() != -1)
399403
{
400404
await Task.Run(() =>
@@ -411,18 +415,26 @@ await Task.Run(() =>
411415
var isSystem = ((FileAttributes)findData.dwFileAttributes & FileAttributes.System) == FileAttributes.System;
412416
var isHidden = ((FileAttributes)findData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden;
413417
var startWithDot = findData.cFileName.StartsWith('.');
418+
var isShortcut = FileExtensionHelpers.IsShortcutOrUrlFile(findData.cFileName);
414419

415420
bool shouldBeListed = (hiddenOnly ?
416-
isHidden && (!isSystem || !UserSettingsService.FoldersSettingsService.ShowProtectedSystemFiles) :
421+
(!isHidden && isShortcut) || (isHidden && UserSettingsService.FoldersSettingsService.ShowHiddenItems && (!isSystem || UserSettingsService.FoldersSettingsService.ShowProtectedSystemFiles)) :
417422
!isHidden || (UserSettingsService.FoldersSettingsService.ShowHiddenItems && (!isSystem || UserSettingsService.FoldersSettingsService.ShowProtectedSystemFiles))) &&
418423
(!startWithDot || UserSettingsService.FoldersSettingsService.ShowDotFiles);
419424

420425
if (shouldBeListed)
421426
{
422-
var item = GetListedItemAsync(itemPath, findData);
423-
if (item is not null)
427+
if (isShortcut)
428+
{
429+
pendingShortcuts.Add((itemPath, findData));
430+
}
431+
else
424432
{
425-
results.Add(item);
433+
var item = GetListedItemAsync(itemPath, findData);
434+
if (item is not null)
435+
{
436+
results.Add(item);
437+
}
426438
}
427439
}
428440

@@ -442,6 +454,121 @@ await Task.Run(() =>
442454
Win32PInvoke.FindClose(hFile);
443455
}, token);
444456
}
457+
458+
foreach (var (itemPath, itemFindData) in pendingShortcuts)
459+
{
460+
if (results.Count >= maxItemCount || token.IsCancellationRequested)
461+
break;
462+
463+
var isUrl = FileExtensionHelpers.IsWebLinkFile(itemFindData.cFileName);
464+
var shortcutFindData = itemFindData;
465+
var isHidden = ((FileAttributes)shortcutFindData.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden;
466+
Win32PInvoke.FileTimeToSystemTime(ref shortcutFindData.ftLastWriteTime, out Win32PInvoke.SYSTEMTIME modifiedTime);
467+
Win32PInvoke.FileTimeToSystemTime(ref shortcutFindData.ftCreationTime, out Win32PInvoke.SYSTEMTIME createdTime);
468+
var fileSize = Win32FindDataExtensions.GetSize(shortcutFindData);
469+
var itemFileExtension = shortcutFindData.cFileName.Contains('.', StringComparison.Ordinal) ? Path.GetExtension(itemPath) : null;
470+
471+
var shortcutItem = new ShortcutItem(null)
472+
{
473+
PrimaryItemAttribute = StorageItemTypes.File,
474+
FileExtension = itemFileExtension,
475+
IsHiddenItem = isHidden,
476+
Opacity = isHidden ? Constants.UI.DimItemOpacity : 1,
477+
FileImage = null,
478+
LoadFileIcon = false,
479+
NeedsPlaceholderGlyph = false,
480+
ItemNameRaw = shortcutFindData.cFileName,
481+
ItemDateModifiedReal = modifiedTime.ToDateTime(),
482+
ItemDateCreatedReal = createdTime.ToDateTime(),
483+
ItemType = isUrl ? Strings.ShortcutWebLinkFileType.GetLocalizedResource() : Strings.Shortcut.GetLocalizedResource(),
484+
ItemPath = itemPath,
485+
FileSize = fileSize.ToSizeString(),
486+
FileSizeBytes = fileSize,
487+
IsUrl = isUrl,
488+
};
489+
490+
if (results.Any(r => string.Equals(r.ItemPath, itemPath, StringComparison.OrdinalIgnoreCase)))
491+
continue;
492+
493+
if (MaxItemCount == 0)
494+
{
495+
_ = FileOperationsHelpers.ParseLinkAsync(itemPath).ContinueWith((t) =>
496+
{
497+
if (t.IsCompletedSuccessfully && t.Result is not null)
498+
{
499+
_ = FilesystemTasks.Wrap(() => MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() =>
500+
{
501+
shortcutItem.TargetPath = t.Result.TargetPath;
502+
shortcutItem.Arguments = t.Result.Arguments;
503+
shortcutItem.WorkingDirectory = t.Result.WorkingDirectory;
504+
shortcutItem.RunAsAdmin = t.Result.RunAsAdmin;
505+
shortcutItem.ShowWindowCommand = t.Result.ShowWindowCommand;
506+
shortcutItem.PrimaryItemAttribute = t.Result.IsFolder ? StorageItemTypes.Folder : StorageItemTypes.File;
507+
}));
508+
}
509+
});
510+
}
511+
else
512+
{
513+
var iconResult = await FileThumbnailHelper.GetIconAsync(
514+
itemPath,
515+
Constants.ShellIconSizes.Small,
516+
false,
517+
IconOptions.ReturnIconOnly | IconOptions.UseCurrentScale);
518+
if (iconResult is not null)
519+
shortcutItem.FileImage = await iconResult.ToBitmapAsync();
520+
else
521+
shortcutItem.NeedsPlaceholderGlyph = true;
522+
}
523+
524+
results.Add(shortcutItem);
525+
526+
if (results.Count == 32 || results.Count % 300 == 0)
527+
{
528+
SearchTick?.Invoke(this, EventArgs.Empty);
529+
}
530+
}
531+
532+
(IntPtr hSubDir, WIN32_FIND_DATA subDirData) = await Task.Run(() =>
533+
{
534+
int additionalFlags = Win32PInvoke.FIND_FIRST_EX_LARGE_FETCH;
535+
IntPtr hSubDirTsk = Win32PInvoke.FindFirstFileExFromApp($"{folder}\\*", Win32PInvoke.FINDEX_INFO_LEVELS.FindExInfoBasic,
536+
out WIN32_FIND_DATA subDirDataTsk, Win32PInvoke.FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, additionalFlags);
537+
return (hSubDirTsk, subDirDataTsk);
538+
}).WithTimeoutAsync(TimeSpan.FromSeconds(5));
539+
540+
if (hSubDir != IntPtr.Zero && hSubDir.ToInt64() != -1)
541+
{
542+
var subDirectories = new List<string>();
543+
544+
await Task.Run(() =>
545+
{
546+
var hasNextDir = false;
547+
do
548+
{
549+
var isDirectory = ((FileAttributes)subDirData.dwFileAttributes & FileAttributes.Directory) == FileAttributes.Directory;
550+
if (isDirectory && subDirData.cFileName != "." && subDirData.cFileName != "..")
551+
{
552+
subDirectories.Add(Path.Combine(folder, subDirData.cFileName));
553+
}
554+
555+
if (token.IsCancellationRequested)
556+
break;
557+
558+
hasNextDir = Win32PInvoke.FindNextFile(hSubDir, out subDirData);
559+
} while (hasNextDir);
560+
561+
Win32PInvoke.FindClose(hSubDir);
562+
}, token);
563+
564+
foreach (var subDir in subDirectories)
565+
{
566+
if (results.Count >= maxItemCount || token.IsCancellationRequested)
567+
break;
568+
569+
await SearchWithWin32Async(subDir, hiddenOnly, maxItemCount - (uint)results.Count, results, token);
570+
}
571+
}
445572
}
446573

447574
private ListedItem GetListedItemAsync(string itemPath, WIN32_FIND_DATA findData)
@@ -596,6 +723,47 @@ private async Task<ListedItem> GetListedItemAsync(IStorageItem item)
596723
ItemOriginalPath = binFile.OriginalPath
597724
};
598725
}
726+
else if (FileExtensionHelpers.IsShortcutOrUrlFile(file.Path))
727+
{
728+
var isUrl = FileExtensionHelpers.IsWebLinkFile(file.Path);
729+
var shortcutItem = new ShortcutItem(null)
730+
{
731+
PrimaryItemAttribute = StorageItemTypes.File,
732+
FileExtension = itemFileExtension,
733+
IsHiddenItem = false,
734+
Opacity = 1,
735+
FileImage = null,
736+
LoadFileIcon = false,
737+
NeedsPlaceholderGlyph = false,
738+
ItemNameRaw = file.Name,
739+
ItemDateModifiedReal = props.DateModified,
740+
ItemDateCreatedReal = file.DateCreated,
741+
ItemType = isUrl ? Strings.ShortcutWebLinkFileType.GetLocalizedResource() : Strings.Shortcut.GetLocalizedResource(),
742+
ItemPath = file.Path,
743+
FileSize = itemSize,
744+
FileSizeBytes = (long)props.Size,
745+
IsUrl = isUrl,
746+
};
747+
if (MaxItemCount == 0)
748+
{
749+
_ = FileOperationsHelpers.ParseLinkAsync(file.Path).ContinueWith((t) =>
750+
{
751+
if (t.IsCompletedSuccessfully && t.Result is not null)
752+
{
753+
_ = FilesystemTasks.Wrap(() => MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() =>
754+
{
755+
shortcutItem.TargetPath = t.Result.TargetPath;
756+
shortcutItem.Arguments = t.Result.Arguments;
757+
shortcutItem.WorkingDirectory = t.Result.WorkingDirectory;
758+
shortcutItem.RunAsAdmin = t.Result.RunAsAdmin;
759+
shortcutItem.ShowWindowCommand = t.Result.ShowWindowCommand;
760+
shortcutItem.PrimaryItemAttribute = t.Result.IsFolder ? StorageItemTypes.Folder : StorageItemTypes.File;
761+
}));
762+
}
763+
});
764+
}
765+
listedItem = shortcutItem;
766+
}
599767
else
600768
{
601769
listedItem = new ListedItem(null)

src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,7 @@ public async Task PopulateOmnibarSuggestionsForSearchMode()
11581158

11591159
// Add new suggestions
11601160
var toAdd = newSuggestions
1161-
.Where(newItem => !OmnibarSearchModeSuggestionItems.Any(existing => existing.Name == newItem.Name));
1161+
.Where(newItem => !OmnibarSearchModeSuggestionItems.Any(existing => existing.ItemPath == newItem.ItemPath));
11621162

11631163
foreach (var item in toAdd)
11641164
OmnibarSearchModeSuggestionItems.Add(item);

0 commit comments

Comments
 (0)