mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
CmdPal: Linq clean-up (All Apps) (#41551)
Beginning the process of removing System.Linq from CmdPal. This PR removes it from the All Apps extension.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CmdPal.Ext.Apps.State;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
@@ -71,26 +71,48 @@ public partial class AllAppsCommandProvider : CommandProvider
|
||||
{
|
||||
var items = _page.GetItems();
|
||||
|
||||
// We're going to do this search in two directions:
|
||||
// First, is this name a substring of any app...
|
||||
var nameMatches = items.Where(i => i.Title.Contains(displayName));
|
||||
var nameMatches = new List<ICommandItem>();
|
||||
ICommandItem? bestAppMatch = null;
|
||||
var bestLength = -1;
|
||||
|
||||
// ... Then, does any app have this name as a substring ...
|
||||
// Only get one of these - "Terminal Preview" contains both "Terminal" and "Terminal Preview", so just take the best one
|
||||
var appMatches = items.Where(i => displayName.Contains(i.Title)).OrderByDescending(i => i.Title.Length).Take(1);
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Title is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// We're going to do this search in two directions:
|
||||
// First, is this name a substring of any app...
|
||||
if (item.Title.Contains(displayName))
|
||||
{
|
||||
nameMatches.Add(item);
|
||||
}
|
||||
|
||||
// ... Then, does any app have this name as a substring ...
|
||||
// Only get one of these - "Terminal Preview" contains both "Terminal" and "Terminal Preview", so just take the best one
|
||||
if (displayName.Contains(item.Title))
|
||||
{
|
||||
if (item.Title.Length > bestLength)
|
||||
{
|
||||
bestLength = item.Title.Length;
|
||||
bestAppMatch = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ... Now, combine those two
|
||||
var both = nameMatches.Concat(appMatches);
|
||||
List<ICommandItem> both = bestAppMatch is null ? nameMatches : [.. nameMatches, bestAppMatch];
|
||||
|
||||
if (both.Count() == 1)
|
||||
if (both.Count == 1)
|
||||
{
|
||||
return both.First();
|
||||
return both[0];
|
||||
}
|
||||
else if (nameMatches.Count() == 1 && appMatches.Count() == 1)
|
||||
else if (nameMatches.Count == 1 && bestAppMatch is not null)
|
||||
{
|
||||
if (nameMatches.First() == appMatches.First())
|
||||
if (nameMatches[0] == bestAppMatch)
|
||||
{
|
||||
return nameMatches.First();
|
||||
return nameMatches[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ManagedCommon;
|
||||
@@ -62,7 +61,9 @@ public sealed partial class AllAppsPage : ListPage
|
||||
{
|
||||
// Build or update the list if needed
|
||||
BuildListItems();
|
||||
return pinnedApps.Concat(unpinnedApps).ToArray();
|
||||
|
||||
AppListItem[] allApps = [.. pinnedApps, .. unpinnedApps];
|
||||
return allApps;
|
||||
}
|
||||
|
||||
private void BuildListItems()
|
||||
@@ -93,16 +94,25 @@ public sealed partial class AllAppsPage : ListPage
|
||||
|
||||
private AppItem[] GetAllApps()
|
||||
{
|
||||
var uwpResults = _appCache.UWPs
|
||||
.Where((application) => application.Enabled)
|
||||
.Select(app => app.ToAppItem());
|
||||
List<AppItem> allApps = new();
|
||||
|
||||
var win32Results = _appCache.Win32s
|
||||
.Where((application) => application.Enabled && application.Valid)
|
||||
.Select(app => app.ToAppItem());
|
||||
foreach (var uwpApp in _appCache.UWPs)
|
||||
{
|
||||
if (uwpApp.Enabled)
|
||||
{
|
||||
allApps.Add(uwpApp.ToAppItem());
|
||||
}
|
||||
}
|
||||
|
||||
var allApps = uwpResults.Concat(win32Results).ToArray();
|
||||
return allApps;
|
||||
foreach (var win32App in _appCache.Win32s)
|
||||
{
|
||||
if (win32App.Enabled && win32App.Valid)
|
||||
{
|
||||
allApps.Add(win32App.ToAppItem());
|
||||
}
|
||||
}
|
||||
|
||||
return [.. allApps];
|
||||
}
|
||||
|
||||
internal (AppItem[] AllApps, AppListItem[] PinnedItems, AppListItem[] UnpinnedItems) GetPrograms()
|
||||
@@ -118,9 +128,7 @@ public sealed partial class AllAppsPage : ListPage
|
||||
|
||||
if (isPinned)
|
||||
{
|
||||
appListItem.Tags = appListItem.Tags
|
||||
.Concat([new Tag() { Icon = Icons.PinIcon }])
|
||||
.ToArray();
|
||||
appListItem.Tags = [.. appListItem.Tags, new Tag() { Icon = Icons.PinIcon }];
|
||||
pinned.Add(appListItem);
|
||||
}
|
||||
else
|
||||
@@ -129,15 +137,14 @@ public sealed partial class AllAppsPage : ListPage
|
||||
}
|
||||
}
|
||||
|
||||
pinned.Sort((a, b) => string.Compare(a.Title, b.Title, StringComparison.Ordinal));
|
||||
unpinned.Sort((a, b) => string.Compare(a.Title, b.Title, StringComparison.Ordinal));
|
||||
|
||||
return (
|
||||
allApps
|
||||
.ToArray(),
|
||||
pinned
|
||||
.OrderBy(app => app.Title)
|
||||
.ToArray(),
|
||||
unpinned
|
||||
.OrderBy(app => app.Title)
|
||||
.ToArray());
|
||||
allApps,
|
||||
pinned.ToArray(),
|
||||
unpinned.ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
private void OnPinStateChanged(object? sender, PinStateChangedEventArgs e)
|
||||
@@ -147,44 +154,55 @@ public sealed partial class AllAppsPage : ListPage
|
||||
* So, instead, we'll just compare pinned items to move existing
|
||||
* items between the two lists.
|
||||
*/
|
||||
var existingAppItem = allApps.FirstOrDefault(f => f.AppIdentifier == e.AppIdentifier);
|
||||
AppItem? existingAppItem = null;
|
||||
|
||||
foreach (var app in allApps)
|
||||
{
|
||||
if (app.AppIdentifier == e.AppIdentifier)
|
||||
{
|
||||
existingAppItem = app;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (existingAppItem is not null)
|
||||
{
|
||||
var appListItem = new AppListItem(existingAppItem, true, e.IsPinned);
|
||||
|
||||
var newPinned = new List<AppListItem>(pinnedApps);
|
||||
var newUnpinned = new List<AppListItem>(unpinnedApps);
|
||||
|
||||
if (e.IsPinned)
|
||||
{
|
||||
// Remove it from the unpinned apps array
|
||||
this.unpinnedApps = this.unpinnedApps
|
||||
.Where(app => app.AppIdentifier != existingAppItem.AppIdentifier)
|
||||
.OrderBy(app => app.Title)
|
||||
.ToArray();
|
||||
|
||||
var newPinned = this.pinnedApps.ToList();
|
||||
newPinned.Add(appListItem);
|
||||
|
||||
this.pinnedApps = newPinned
|
||||
.OrderBy(app => app.Title)
|
||||
.ToArray();
|
||||
foreach (var app in newUnpinned)
|
||||
{
|
||||
if (app.AppIdentifier == e.AppIdentifier)
|
||||
{
|
||||
newUnpinned.Remove(app);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove it from the pinned apps array
|
||||
this.pinnedApps = this.pinnedApps
|
||||
.Where(app => app.AppIdentifier != existingAppItem.AppIdentifier)
|
||||
.OrderBy(app => app.Title)
|
||||
.ToArray();
|
||||
|
||||
var newUnpinned = this.unpinnedApps.ToList();
|
||||
newUnpinned.Add(appListItem);
|
||||
|
||||
this.unpinnedApps = newUnpinned
|
||||
.OrderBy(app => app.Title)
|
||||
.ToArray();
|
||||
foreach (var app in newPinned)
|
||||
{
|
||||
if (app.AppIdentifier == e.AppIdentifier)
|
||||
{
|
||||
newPinned.Remove(app);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RaiseItemsChanged(0);
|
||||
pinnedApps = newPinned.ToArray();
|
||||
unpinnedApps = newUnpinned.ToArray();
|
||||
}
|
||||
|
||||
RaiseItemsChanged(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
using Microsoft.CmdPal.Ext.Apps.Storage;
|
||||
@@ -31,7 +30,10 @@ public sealed partial class AppCache : IAppCache, IDisposable
|
||||
public AppCache()
|
||||
{
|
||||
_win32ProgramRepositoryHelper = new Win32ProgramFileSystemWatchers();
|
||||
_win32ProgramRepository = new Win32ProgramRepository(_win32ProgramRepositoryHelper.FileSystemWatchers.Cast<IFileSystemWatcherWrapper>().ToList(), AllAppsSettings.Instance, _win32ProgramRepositoryHelper.PathsToWatch);
|
||||
|
||||
var watchers = new List<IFileSystemWatcherWrapper>(_win32ProgramRepositoryHelper.FileSystemWatchers);
|
||||
|
||||
_win32ProgramRepository = new Win32ProgramRepository(watchers, AllAppsSettings.Instance, _win32ProgramRepositoryHelper.PathsToWatch);
|
||||
|
||||
_packageRepository = new PackageRepository(new PackageCatalogWrapper());
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps;
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
// 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;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.Apps.State;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using Windows.Management.Deployment;
|
||||
|
||||
@@ -26,9 +25,19 @@ public class PackageManagerWrapper : IPackageManager
|
||||
{
|
||||
var pkgs = _packageManager.FindPackagesForUser(user.Value);
|
||||
|
||||
return pkgs.Select(PackageWrapper.GetWrapperFromPackage).Where(package => package is not null);
|
||||
ICollection<IPackage> packages = [];
|
||||
|
||||
foreach (var package in pkgs)
|
||||
{
|
||||
if (package is not null)
|
||||
{
|
||||
packages.Add(PackageWrapper.GetWrapperFromPackage(package));
|
||||
}
|
||||
}
|
||||
|
||||
return packages;
|
||||
}
|
||||
|
||||
return Enumerable.Empty<IPackage>();
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using ManagedCommon;
|
||||
@@ -72,18 +71,20 @@ public partial class UWP
|
||||
PInvoke.SHCreateStreamOnFileEx(path, STGMREAD, noAttribute, false, null, &stream).ThrowOnFailure();
|
||||
using var streamHandle = new SafeComHandle((IntPtr)stream);
|
||||
|
||||
Apps = AppxPackageHelper.GetAppsFromManifest(stream).Select(appInManifest =>
|
||||
var appsInManifest = AppxPackageHelper.GetAppsFromManifest(stream);
|
||||
|
||||
foreach (var appInManifest in appsInManifest)
|
||||
{
|
||||
using var appHandle = new SafeComHandle(appInManifest);
|
||||
return new UWPApplication((IAppxManifestApplication*)appInManifest, this);
|
||||
}).Where(a =>
|
||||
{
|
||||
var valid =
|
||||
!string.IsNullOrEmpty(a.UserModelId) &&
|
||||
!string.IsNullOrEmpty(a.DisplayName) &&
|
||||
a.AppListEntry != "none";
|
||||
return valid;
|
||||
}).ToList();
|
||||
var uwpApp = new UWPApplication((IAppxManifestApplication*)appInManifest, this);
|
||||
|
||||
if (!string.IsNullOrEmpty(uwpApp.UserModelId) &&
|
||||
!string.IsNullOrEmpty(uwpApp.DisplayName) &&
|
||||
uwpApp.AppListEntry != "none")
|
||||
{
|
||||
Apps.Add(uwpApp);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -93,19 +94,31 @@ public partial class UWP
|
||||
}
|
||||
}
|
||||
|
||||
// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
|
||||
private static string[] XmlNamespaces(string path)
|
||||
{
|
||||
var z = XDocument.Load(path);
|
||||
if (z.Root is not null)
|
||||
{
|
||||
var namespaces = z.Root.Attributes().
|
||||
Where(a => a.IsNamespaceDeclaration).
|
||||
GroupBy(
|
||||
a => a.Name.Namespace == XNamespace.None ? string.Empty : a.Name.LocalName,
|
||||
a => XNamespace.Get(a.Value)).Select(
|
||||
g => g.First().ToString()).ToArray();
|
||||
return namespaces;
|
||||
var namespaces = new HashSet<string>();
|
||||
|
||||
var attributes = z.Root.Attributes();
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
if (attribute.IsNamespaceDeclaration)
|
||||
{
|
||||
// Extract namespace
|
||||
var key = attribute.Name.Namespace == XNamespace.None ? string.Empty : attribute.Name.LocalName;
|
||||
XNamespace ns = XNamespace.Get(attribute.Value);
|
||||
var nsString = ns.ToString();
|
||||
|
||||
// Use HashSet to check for duplicates
|
||||
namespaces.Add(nsString);
|
||||
}
|
||||
}
|
||||
|
||||
var uniqueNamespaces = new string[namespaces.Count];
|
||||
namespaces.CopyTo(uniqueNamespaces);
|
||||
return uniqueNamespaces;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -115,10 +128,13 @@ public partial class UWP
|
||||
|
||||
private void InitPackageVersion(string[] namespaces)
|
||||
{
|
||||
foreach (var n in _versionFromNamespace.Keys.Where(namespaces.Contains))
|
||||
foreach (var n in _versionFromNamespace.Keys)
|
||||
{
|
||||
Version = _versionFromNamespace[n];
|
||||
return;
|
||||
if (Array.IndexOf(namespaces, n) >= 0)
|
||||
{
|
||||
Version = _versionFromNamespace[n];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Version = PackageVersion.Unknown;
|
||||
@@ -137,7 +153,18 @@ public partial class UWP
|
||||
|
||||
foreach (var app in u.Apps)
|
||||
{
|
||||
if (AllAppsSettings.Instance.DisabledProgramSources.All(x => x.UniqueIdentifier != app.UniqueIdentifier))
|
||||
var isDisabled = false;
|
||||
|
||||
foreach (var disabled in AllAppsSettings.Instance.DisabledProgramSources)
|
||||
{
|
||||
if (disabled.UniqueIdentifier == app.UniqueIdentifier)
|
||||
{
|
||||
isDisabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDisabled)
|
||||
{
|
||||
appsBag.Add(app);
|
||||
}
|
||||
@@ -154,20 +181,28 @@ public partial class UWP
|
||||
|
||||
private static IEnumerable<IPackage> CurrentUserPackages()
|
||||
{
|
||||
return PackageManagerWrapper.FindPackagesForCurrentUser().Where(p =>
|
||||
var currentUsersPackages = PackageManagerWrapper.FindPackagesForCurrentUser();
|
||||
ICollection<IPackage> packagesToReturn = [];
|
||||
|
||||
foreach (var pkg in currentUsersPackages)
|
||||
{
|
||||
try
|
||||
{
|
||||
var f = p.IsFramework;
|
||||
var path = p.InstalledLocation;
|
||||
return !f && !string.IsNullOrEmpty(path);
|
||||
var f = pkg.IsFramework;
|
||||
var path = pkg.InstalledLocation;
|
||||
|
||||
if (!f && !string.IsNullOrEmpty(path))
|
||||
{
|
||||
packagesToReturn.Add(pkg);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return packagesToReturn;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Commands;
|
||||
@@ -348,20 +347,22 @@ public class UWPApplication : IUWPApplication
|
||||
//
|
||||
// FirstOrDefault would result in us using the 1x scaled icon
|
||||
// always, which is usually too small for our needs.
|
||||
var selectedIconPath = paths.LastOrDefault(File.Exists);
|
||||
if (!string.IsNullOrEmpty(selectedIconPath))
|
||||
for (var i = paths.Count - 1; i >= 0; i--)
|
||||
{
|
||||
LogoPath = selectedIconPath;
|
||||
if (highContrast)
|
||||
if (File.Exists(paths[i]))
|
||||
{
|
||||
LogoType = LogoType.HighContrast;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogoType = LogoType.Colored;
|
||||
}
|
||||
LogoPath = paths[i];
|
||||
if (highContrast)
|
||||
{
|
||||
LogoType = LogoType.HighContrast;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogoType = LogoType.Colored;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +403,23 @@ public class UWPApplication : IUWPApplication
|
||||
}
|
||||
}
|
||||
|
||||
var selectedIconPath = paths.OrderBy(x => Math.Abs(pathFactorPairs.GetValueOrDefault(x) - appIconSize)).FirstOrDefault(File.Exists);
|
||||
// Sort paths by distance to desired app icon size
|
||||
var selectedIconPath = string.Empty;
|
||||
var closestDistance = int.MaxValue;
|
||||
|
||||
foreach (var p in paths)
|
||||
{
|
||||
if (File.Exists(p) && pathFactorPairs.TryGetValue(p, out var factor))
|
||||
{
|
||||
var distance = Math.Abs(factor - appIconSize);
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
closestDistance = distance;
|
||||
selectedIconPath = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedIconPath))
|
||||
{
|
||||
LogoPath = selectedIconPath;
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
@@ -616,9 +615,24 @@ public class Win32Program : IProgram
|
||||
}
|
||||
|
||||
private static IEnumerable<string> CustomProgramPaths(IEnumerable<ProgramSource> sources, IList<string> suffixes)
|
||||
=> sources?.Where(programSource => Directory.Exists(programSource.Location) && programSource.Enabled)
|
||||
.SelectMany(programSource => ProgramPaths(programSource.Location, suffixes))
|
||||
.ToList() ?? Enumerable.Empty<string>();
|
||||
{
|
||||
if (sources is not null)
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
foreach (var programSource in sources)
|
||||
{
|
||||
if (Directory.Exists(programSource.Location) && programSource.Enabled)
|
||||
{
|
||||
paths.AddRange(ProgramPaths(programSource.Location, suffixes));
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
// Function to obtain the list of applications, the locations of which have been added to the env variable PATH
|
||||
private static List<string> PathEnvironmentProgramPaths(IList<string> suffixes)
|
||||
@@ -647,9 +661,15 @@ public class Win32Program : IProgram
|
||||
}
|
||||
|
||||
private static List<string> IndexPath(IList<string> suffixes, List<string> indexLocations)
|
||||
=> indexLocations
|
||||
.SelectMany(indexLocation => ProgramPaths(indexLocation, suffixes))
|
||||
.ToList();
|
||||
{
|
||||
var paths = new List<string>();
|
||||
foreach (var indexLocation in indexLocations)
|
||||
{
|
||||
paths.AddRange(ProgramPaths(indexLocation, suffixes));
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
private static List<string> StartMenuProgramPaths(IList<string> suffixes)
|
||||
{
|
||||
@@ -691,17 +711,51 @@ public class Win32Program : IProgram
|
||||
}
|
||||
}
|
||||
|
||||
return paths
|
||||
.Where(path => suffixes.Any(suffix => path.EndsWith(suffix, StringComparison.InvariantCultureIgnoreCase)))
|
||||
.Select(ExpandEnvironmentVariables)
|
||||
.Where(path => path is not null)
|
||||
.ToList();
|
||||
var returnedPaths = new List<string>();
|
||||
foreach (var path in paths)
|
||||
{
|
||||
var matchesSuffix = false;
|
||||
foreach (var suffix in suffixes)
|
||||
{
|
||||
if (path.EndsWith(suffix, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
matchesSuffix = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchesSuffix)
|
||||
{
|
||||
var expandedPath = ExpandEnvironmentVariables(path);
|
||||
if (expandedPath is not null)
|
||||
{
|
||||
returnedPaths.Add(expandedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnedPaths;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetPathsFromRegistry(RegistryKey root)
|
||||
=> root
|
||||
.GetSubKeyNames()
|
||||
.Select(x => GetPathFromRegistrySubkey(root, x));
|
||||
{
|
||||
var result = new List<string>();
|
||||
|
||||
// Get all subkey names
|
||||
var subKeyNames = root.GetSubKeyNames();
|
||||
|
||||
// Process each subkey to extract the path
|
||||
foreach (var subkeyName in subKeyNames)
|
||||
{
|
||||
var path = GetPathFromRegistrySubkey(root, subkeyName);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
result.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetPathFromRegistrySubkey(RegistryKey root, string subkey)
|
||||
{
|
||||
@@ -765,7 +819,28 @@ public class Win32Program : IProgram
|
||||
}
|
||||
|
||||
public static List<Win32Program> DeduplicatePrograms(IEnumerable<Win32Program> programs)
|
||||
=> new HashSet<Win32Program>(programs, Win32ProgramEqualityComparer.Default).ToList();
|
||||
{
|
||||
// Create a HashSet with the custom equality comparer to automatically deduplicate programs
|
||||
var uniquePrograms = new HashSet<Win32Program>(Win32ProgramEqualityComparer.Default);
|
||||
|
||||
// Filter out invalid programs and add valid ones to the HashSet
|
||||
foreach (var program in programs)
|
||||
{
|
||||
if (program?.Valid == true)
|
||||
{
|
||||
uniquePrograms.Add(program);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the HashSet to a List for return
|
||||
var result = new List<Win32Program>(uniquePrograms.Count);
|
||||
foreach (var program in uniquePrograms)
|
||||
{
|
||||
result.Add(program);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Win32Program GetProgramFromPath(string path)
|
||||
{
|
||||
@@ -881,8 +956,22 @@ public class Win32Program : IProgram
|
||||
|
||||
foreach (var path in source.GetPaths())
|
||||
{
|
||||
if (disabledProgramsList.All(x => x.UniqueIdentifier != path) &&
|
||||
!ExecutableApplicationExtensions.Contains(Extension(path)))
|
||||
if (ExecutableApplicationExtensions.Contains(Extension(path)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var isDisabled = false;
|
||||
foreach (var disabledProgram in disabledProgramsList)
|
||||
{
|
||||
if (disabledProgram.UniqueIdentifier == path)
|
||||
{
|
||||
isDisabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDisabled)
|
||||
{
|
||||
pathBag.Add(path);
|
||||
}
|
||||
@@ -902,7 +991,17 @@ public class Win32Program : IProgram
|
||||
|
||||
foreach (var path in source.GetPaths())
|
||||
{
|
||||
if (disabledProgramsList.All(x => x.UniqueIdentifier != path))
|
||||
var isDisabled = false;
|
||||
foreach (var disabledProgram in disabledProgramsList)
|
||||
{
|
||||
if (disabledProgram.UniqueIdentifier == path)
|
||||
{
|
||||
isDisabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDisabled)
|
||||
{
|
||||
runCommandPathBag.Add(path);
|
||||
}
|
||||
@@ -931,10 +1030,8 @@ public class Win32Program : IProgram
|
||||
}
|
||||
});
|
||||
|
||||
var programs = programsList.ToList();
|
||||
var runCommandPrograms = runCommandProgramsList.ToList();
|
||||
|
||||
return DeduplicatePrograms(programs.Concat(runCommandPrograms).Where(program => program?.Valid == true));
|
||||
List<Win32Program> allPrograms = [.. programsList, .. runCommandProgramsList];
|
||||
return DeduplicatePrograms(allPrograms);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.State;
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
@@ -31,7 +29,7 @@ public sealed class PinnedAppsManager
|
||||
|
||||
public bool IsAppPinned(string appIdentifier)
|
||||
{
|
||||
return _pinnedApps.PinnedAppIdentifiers.Contains(appIdentifier, StringComparer.OrdinalIgnoreCase);
|
||||
return _pinnedApps.PinnedAppIdentifiers.IndexOf(appIdentifier) >= 0;
|
||||
}
|
||||
|
||||
public void PinApp(string appIdentifier)
|
||||
|
||||
@@ -6,7 +6,6 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ManagedCommon;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Storage;
|
||||
@@ -20,7 +19,16 @@ public class ListRepository<T> : IRepository<T>, IEnumerable<T>
|
||||
{
|
||||
public IList<T> Items
|
||||
{
|
||||
get { return _items.Values.ToList(); }
|
||||
get
|
||||
{
|
||||
var items = new List<T>(_items.Count);
|
||||
foreach (var item in _items.Values)
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<int, T> _items = new ConcurrentDictionary<int, T>();
|
||||
@@ -34,9 +42,16 @@ public class ListRepository<T> : IRepository<T>, IEnumerable<T>
|
||||
// enforce that internal representation
|
||||
try
|
||||
{
|
||||
var result = new ConcurrentDictionary<int, T>();
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
_items = new ConcurrentDictionary<int, T>(list.ToDictionary(i => i.GetHashCode()));
|
||||
result.TryAdd(item.GetHashCode(), item);
|
||||
#pragma warning restore CS8602 // Dereference of a possibly null reference.
|
||||
}
|
||||
|
||||
_items = result;
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
using Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
@@ -104,10 +103,14 @@ internal sealed partial class PackageRepository : ListRepository<IUWPApplication
|
||||
// find apps associated with this package.
|
||||
var packageWrapper = PackageWrapper.GetWrapperFromPackage(package);
|
||||
var uwp = new UWP(packageWrapper);
|
||||
var apps = Items.Where(a => a.Package.Equals(uwp)).ToArray();
|
||||
|
||||
foreach (var app in apps)
|
||||
foreach (var app in Items)
|
||||
{
|
||||
if (!app.Package.Equals(uwp))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Remove(app);
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ManagedCommon;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Storage;
|
||||
@@ -55,7 +54,16 @@ internal sealed partial class Win32ProgramFileSystemWatchers : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
return paths.Except(invalidPaths).ToArray();
|
||||
var validPaths = new List<string>();
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if (!invalidPaths.Contains(path))
|
||||
{
|
||||
validPaths.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
return validPaths.ToArray();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
// 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.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
// 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;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
|
||||
public enum Theme
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
@@ -56,15 +55,25 @@ public static class ThemeHelper
|
||||
return Theme.Light; // Default to light theme if missing
|
||||
}
|
||||
|
||||
var theme = themePath.Split('\\').Last().Split('.').First().ToLowerInvariant();
|
||||
|
||||
return theme switch
|
||||
var splitThemePath = themePath.Split('\\');
|
||||
if (splitThemePath.Length > 0)
|
||||
{
|
||||
"hc1" => Theme.HighContrastOne,
|
||||
"hc2" => Theme.HighContrastTwo,
|
||||
"hcwhite" => Theme.HighContrastWhite,
|
||||
"hcblack" => Theme.HighContrastBlack,
|
||||
_ => Theme.Light,
|
||||
};
|
||||
var lastSegment = splitThemePath[splitThemePath.Length - 1];
|
||||
var splitSegment = lastSegment.Split('.');
|
||||
if (splitSegment.Length > 0)
|
||||
{
|
||||
var themeVariant = splitSegment[0].ToLowerInvariant();
|
||||
return themeVariant switch
|
||||
{
|
||||
"hc1" => Theme.HighContrastOne,
|
||||
"hc2" => Theme.HighContrastTwo,
|
||||
"hcwhite" => Theme.HighContrastWhite,
|
||||
"hcblack" => Theme.HighContrastBlack,
|
||||
_ => Theme.Light,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return Theme.Light;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user