Skip to content

Commit 8c35281

Browse files
authored
Merge pull request #3 from licon4812/dotnet-tools
Added Support for dotnet tools, and added Cake & File Based App support to NuGet Packages
2 parents ff67df0 + 2060cd0 commit 8c35281

5 files changed

Lines changed: 173 additions & 3 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Addin/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

src/NuGetPackageSearchCmdPalExtension/NuGetPackageSearchCmdPalExtensionCommandsProvider.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ public NuGetPackageSearchCmdPalExtensionCommandsProvider()
1717
Icon = IconHelpers.FromRelativePath("Assets\\StoreLogo.png");
1818
_commands = [
1919
new CommandItem(new Pages.SearchNuGetPackagesPage()) { Title = "Search NuGet Packages" },
20-
new CommandItem(new Pages.SearchDotnetTemplatesPage()) {Title = "Search Dotnet Templates"}
20+
new CommandItem(new Pages.SearchDotnetTemplatesPage()) {Title = "Search Dotnet Templates"},
21+
new CommandItem(new Pages.SearchDotnetToolsPage()){Title = "Search Dotnet Tools"}
2122
];
2223
}
2324

src/NuGetPackageSearchCmdPalExtension/Package.appxmanifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<Identity
1313
Name="23610AlickolliSoftware.NuGetPackageSearchforComman"
1414
Publisher="CN=5CECD841-CF4E-45AF-B443-573F4A3614A0"
15-
Version="0.0.3.0" />
15+
Version="0.0.4.0" />
1616
<!-- When you're ready to publish your extension, you'll need to change the
1717
Publisher= to match your own identity -->
1818

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using Microsoft.CommandPalette.Extensions;
2+
using Microsoft.CommandPalette.Extensions.Toolkit;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Diagnostics;
6+
using System.Linq;
7+
using System.Net.Http;
8+
using System.Text;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using System.Threading.Tasks.Dataflow;
12+
using Windows.ApplicationModel;
13+
14+
namespace NuGetPackageSearchCmdPalExtension.Pages
15+
{
16+
internal sealed partial class SearchDotnetToolsPage : DynamicListPage, IDisposable
17+
{
18+
private bool _isError;
19+
private readonly CancellationTokenSource _cancellationTokenSource = new();
20+
private readonly BufferBlock<string> _searchTextBuffer = new();
21+
private IReadOnlyList<ListItem> _results = [];
22+
23+
public SearchDotnetToolsPage()
24+
{
25+
// Retrieve the app version
26+
var version = Package.Current.Id.Version;
27+
var appVersion = $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
28+
29+
Icon = new IconInfo("\uE773");
30+
Title = $"NuGet Package Search Extension - v{appVersion}";
31+
Name = "Search";
32+
33+
// Configure the search processing pipeline
34+
Task.Run(async () =>
35+
{
36+
while (await _searchTextBuffer.OutputAvailableAsync(_cancellationTokenSource.Token))
37+
{
38+
var searchText = await _searchTextBuffer.ReceiveAsync(_cancellationTokenSource.Token);
39+
IsLoading = true;
40+
try
41+
{
42+
_results = await ProcessSearchAsync(searchText, _cancellationTokenSource.Token);
43+
_isError = false;
44+
}
45+
catch
46+
{
47+
_isError = true;
48+
_results = [];
49+
}
50+
finally
51+
{
52+
IsLoading = false;
53+
RaiseItemsChanged(_results!.Count);
54+
}
55+
}
56+
}, _cancellationTokenSource.Token);
57+
}
58+
59+
public override IListItem[] GetItems()
60+
{
61+
return [.. _results];
62+
}
63+
64+
public override void UpdateSearchText(string oldSearch, string newSearch)
65+
{
66+
if (newSearch == oldSearch) return;
67+
_searchTextBuffer.Post(newSearch);
68+
}
69+
70+
public void Dispose()
71+
{
72+
_cancellationTokenSource.Cancel();
73+
_cancellationTokenSource.Dispose();
74+
}
75+
76+
public override ICommandItem? EmptyContent
77+
{
78+
get
79+
{
80+
if (_isError)
81+
{
82+
return new CommandItem
83+
{
84+
Title = "Error loading dotnet tools",
85+
Icon = new IconInfo("\uea39"),
86+
Subtitle = "An error occurred while fetching dotnet tools.",
87+
Command = new NoOpCommand()
88+
};
89+
}
90+
91+
return new CommandItem
92+
{
93+
Title = "Search for a dotnet tools",
94+
Icon = new IconInfo("\uea39"),
95+
Subtitle = "Search for a dotnet tools",
96+
Command = new NoOpCommand()
97+
}; ;
98+
}
99+
}
100+
101+
private static async Task<IReadOnlyList<ListItem>> ProcessSearchAsync(string searchText, CancellationToken cancellationToken)
102+
{
103+
await Task.Yield(); // Simulate asynchronous behavior
104+
105+
var url = $"https://azuresearch-usnc.nuget.org/query?take=20&packageType=DotnetTool&q={Uri.EscapeDataString(searchText)}";
106+
using var httpClient = new HttpClient();
107+
using var response = await httpClient.GetAsync(url, cancellationToken);
108+
response.EnsureSuccessStatusCode();
109+
110+
var json = await response.Content.ReadAsStringAsync(cancellationToken);
111+
112+
using var doc = System.Text.Json.JsonDocument.Parse(json);
113+
var results = new List<ListItem>();
114+
115+
if (!doc.RootElement.TryGetProperty("data", out var dataElement) ||
116+
dataElement.ValueKind != System.Text.Json.JsonValueKind.Array) return results;
117+
118+
foreach (var package in dataElement.EnumerateArray())
119+
{
120+
var id = package.GetProperty("id").GetString();
121+
var version = package.GetProperty("version").GetString();
122+
string? iconUrl = null;
123+
if (package.TryGetProperty("iconUrl", out var iconUrlProp) && iconUrlProp.ValueKind == System.Text.Json.JsonValueKind.String)
124+
{
125+
iconUrl = iconUrlProp.GetString();
126+
}
127+
// Fallback to a glyph if iconUrl is missing
128+
var icon = !string.IsNullOrEmpty(iconUrl) ? new IconInfo(iconUrl) : new IconInfo("\uE7B8");
129+
results.Add(new ListItem
130+
{
131+
Title = id!,
132+
Subtitle = version!,
133+
Icon = icon,
134+
Command = new CopyTextCommand($"dotnet tool install --global {id} --version {version}") { Name = "Copy global install Command" },
135+
MoreCommands =
136+
[
137+
new CommandContextItem(new AnonymousCommand(() =>
138+
{
139+
var startInfo = new ProcessStartInfo
140+
{
141+
FileName = "cmd.exe",
142+
Arguments = $"/k dotnet tool install --global {id} --version {version}", // Use /k to keep the shell open
143+
UseShellExecute = true,
144+
CreateNoWindow = false
145+
};
146+
147+
using var process = new Process();
148+
process.StartInfo = startInfo;
149+
process.Start();
150+
process.WaitForExit();
151+
}){Icon = new IconInfo("\uE896"), Name = "Install tool globally"}),
152+
new CommandContextItem(new CopyTextCommand($"dotnet tool install --local {id} --version {version}"){Name = "Copy local install command"}),
153+
new CommandContextItem(new CopyTextCommand($"#tool dotnet:?package={id}&version={version}"){Name = "Copy cake tool"}),
154+
new CommandContextItem(new CopyTextCommand($"nuke :add-package {id} --version {version}"){Name = "Copy NUKE"})
155+
156+
]
157+
});
158+
}
159+
160+
return results;
161+
}
162+
}
163+
}

src/NuGetPackageSearchCmdPalExtension/Pages/SearchNuGetPackagesPage.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,11 @@ private static async Task<IReadOnlyList<ListItem>> ProcessSearchAsync(string sea
139139
new CommandContextItem(new CopyTextCommand($"<PackageReference Include=\"{id}\" Version=\"{version}\" />"){Name = "Copy Package Reference"}),
140140
new CommandContextItem(new CopyTextCommand($"dotnet add package {id} --version {version}"){Name = "Copy .NET CLI command"}),
141141
new CommandContextItem(new CopyTextCommand($"NuGet\\Install-Package {id} -Version {version}"){Name = "Copy Nuget Package Manager command"}),
142-
new CommandContextItem(new CopyTextCommand($"#r \"nuget: {id}, {version}\""){Name = "Copy Script & Interactive"})
142+
new CommandContextItem(new CopyTextCommand($"#r \"nuget: {id}, {version}\""){Name = "Copy Script & Interactive"}),
143+
new CommandContextItem(new CopyTextCommand($"#:package {id}@{version}"){Name = "Copy File-based Apps"}),
144+
new CommandContextItem(new CopyTextCommand($"#addin nuget:?package={id}={version}"){Name = "Copy Cake Addin"}),
145+
new CommandContextItem(new CopyTextCommand($"#tool nuget:?package={id}&version={version}"){Name = "Copy Cake Tool"})
146+
143147
]
144148
});
145149
}

0 commit comments

Comments
 (0)