mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-30 08:56:33 +01:00
Compare commits
39 Commits
jay/DarkMo
...
yuleng/cmd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5164a1f861 | ||
|
|
553c7eb0c7 | ||
|
|
5323dea50d | ||
|
|
d5e01fc924 | ||
|
|
b631615c54 | ||
|
|
7bbe1f68d4 | ||
|
|
897a71ecc3 | ||
|
|
44b677b16d | ||
|
|
425b8c2cf8 | ||
|
|
56c8b57fe5 | ||
|
|
b17d53c485 | ||
|
|
4a2cb8014f | ||
|
|
dfea4c269c | ||
|
|
0aeeebcc74 | ||
|
|
a51b222cee | ||
|
|
48184d6240 | ||
|
|
b825f7a0ff | ||
|
|
242dff4a29 | ||
|
|
ae0da4ea08 | ||
|
|
9ee9824ca9 | ||
|
|
962cb4324f | ||
|
|
9b25427847 | ||
|
|
dc69a83905 | ||
|
|
d7dbe0d9c9 | ||
|
|
a0827b0074 | ||
|
|
0efb642ec0 | ||
|
|
df252dbb5a | ||
|
|
8d2b3f2ec2 | ||
|
|
c39bda96b0 | ||
|
|
d220051419 | ||
|
|
3db59a30b9 | ||
|
|
681d9a26bd | ||
|
|
038ace0666 | ||
|
|
84727c8b47 | ||
|
|
923e33a067 | ||
|
|
9f8a238e84 | ||
|
|
e6abca9b73 | ||
|
|
311b8acaa7 | ||
|
|
e5f9d4b643 |
@@ -4,6 +4,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks;
|
||||
|
||||
|
||||
@@ -8,10 +8,14 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Helpers;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Properties;
|
||||
using Microsoft.CmdPal.Ext.Indexer;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Microsoft.Diagnostics.Utilities;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks;
|
||||
|
||||
@@ -23,10 +27,6 @@ public partial class BookmarksCommandProvider : CommandProvider
|
||||
|
||||
private Bookmarks? _bookmarks;
|
||||
|
||||
public static IconInfo DeleteIcon { get; private set; } = new("\uE74D"); // Delete
|
||||
|
||||
public static IconInfo EditIcon { get; private set; } = new("\uE70F"); // Edit
|
||||
|
||||
public BookmarksCommandProvider()
|
||||
{
|
||||
Id = "Bookmarks";
|
||||
@@ -109,57 +109,23 @@ public partial class BookmarksCommandProvider : CommandProvider
|
||||
|
||||
private CommandItem BookmarkToCommandItem(BookmarkData bookmark)
|
||||
{
|
||||
ICommand command = bookmark.IsPlaceholder ?
|
||||
new BookmarkPlaceholderPage(bookmark) :
|
||||
new UrlCommand(bookmark);
|
||||
|
||||
var listItem = new CommandItem(command) { Icon = command.Icon };
|
||||
|
||||
List<CommandContextItem> contextMenu = [];
|
||||
|
||||
// Add commands for folder types
|
||||
if (command is UrlCommand urlCommand)
|
||||
var deleteAction = () =>
|
||||
{
|
||||
if (urlCommand.Type == "folder")
|
||||
if (_bookmarks != null)
|
||||
{
|
||||
contextMenu.Add(
|
||||
new CommandContextItem(new DirectoryPage(urlCommand.Url)));
|
||||
ExtensionHost.LogMessage($"Deleting bookmark ({bookmark.Name},{bookmark.Bookmark})");
|
||||
|
||||
contextMenu.Add(
|
||||
new CommandContextItem(new OpenInTerminalCommand(urlCommand.Url)));
|
||||
_bookmarks.Data.Remove(bookmark);
|
||||
SaveAndUpdateCommands();
|
||||
}
|
||||
};
|
||||
|
||||
listItem.Subtitle = urlCommand.Url;
|
||||
if (bookmark.IsPlaceholder)
|
||||
{
|
||||
return CreatePlaceholderCommand(bookmark, Edit_AddedCommand, deleteAction);
|
||||
}
|
||||
|
||||
var edit = new AddBookmarkPage(bookmark) { Icon = EditIcon };
|
||||
edit.AddedCommand += Edit_AddedCommand;
|
||||
contextMenu.Add(new CommandContextItem(edit));
|
||||
|
||||
var delete = new CommandContextItem(
|
||||
title: Resources.bookmarks_delete_title,
|
||||
name: Resources.bookmarks_delete_name,
|
||||
action: () =>
|
||||
{
|
||||
if (_bookmarks != null)
|
||||
{
|
||||
ExtensionHost.LogMessage($"Deleting bookmark ({bookmark.Name},{bookmark.Bookmark})");
|
||||
|
||||
_bookmarks.Data.Remove(bookmark);
|
||||
|
||||
SaveAndUpdateCommands();
|
||||
}
|
||||
},
|
||||
result: CommandResult.KeepOpen())
|
||||
{
|
||||
IsCritical = true,
|
||||
Icon = DeleteIcon,
|
||||
};
|
||||
contextMenu.Add(delete);
|
||||
|
||||
listItem.MoreCommands = contextMenu.ToArray();
|
||||
|
||||
return listItem;
|
||||
return CreateShellCommand(bookmark, Edit_AddedCommand, deleteAction);
|
||||
}
|
||||
|
||||
public override ICommandItem[] TopLevelCommands()
|
||||
@@ -180,4 +146,64 @@ public partial class BookmarksCommandProvider : CommandProvider
|
||||
// now, the state is just next to the exe
|
||||
return System.IO.Path.Combine(directory, "bookmarks.json");
|
||||
}
|
||||
|
||||
private static CommandItem CreatePlaceholderCommand(BookmarkData bookmark, TypedEventHandler<object, BookmarkData> addBookmarkFunc, Action deleteAction)
|
||||
{
|
||||
var command = new BookmarkPlaceholderPage(bookmark);
|
||||
var listItem = new CommandItem(command) { Icon = command.Icon };
|
||||
List<CommandContextItem> contextMenu = [];
|
||||
|
||||
var edit = new AddBookmarkPage(bookmark) { Icon = IconHelper.EditIcon };
|
||||
edit.AddedCommand += addBookmarkFunc;
|
||||
contextMenu.Add(new CommandContextItem(edit));
|
||||
var delete = new CommandContextItem(
|
||||
title: Resources.bookmarks_delete_title,
|
||||
name: Resources.bookmarks_delete_name,
|
||||
action: deleteAction,
|
||||
result: CommandResult.KeepOpen())
|
||||
{
|
||||
IsCritical = true,
|
||||
Icon = IconHelper.DeleteIcon,
|
||||
};
|
||||
contextMenu.Add(delete);
|
||||
listItem.MoreCommands = contextMenu.ToArray();
|
||||
return listItem;
|
||||
}
|
||||
|
||||
private static CommandItem CreateShellCommand(BookmarkData bookmark, TypedEventHandler<object, BookmarkData> addBookmarkFunc, Action deleteAction)
|
||||
{
|
||||
var invokableCommand = new Command.ShellCommand(bookmark);
|
||||
var listItem = new CommandItem(invokableCommand) { Icon = invokableCommand.Icon };
|
||||
|
||||
List<CommandContextItem> contextMenu = [];
|
||||
|
||||
if (bookmark.Type == BookmarkType.Folder)
|
||||
{
|
||||
contextMenu.Add(
|
||||
new CommandContextItem(new DirectoryPage(bookmark.Bookmark)));
|
||||
contextMenu.Add(
|
||||
new CommandContextItem(new OpenInTerminalCommand(bookmark.Bookmark)));
|
||||
}
|
||||
|
||||
listItem.Subtitle = invokableCommand.BookmarkData.Bookmark;
|
||||
|
||||
var edit = new AddBookmarkPage(bookmark) { Icon = IconHelper.EditIcon };
|
||||
edit.AddedCommand += addBookmarkFunc;
|
||||
contextMenu.Add(new CommandContextItem(edit));
|
||||
|
||||
var delete = new CommandContextItem(
|
||||
title: Resources.bookmarks_delete_title,
|
||||
name: Resources.bookmarks_delete_name,
|
||||
action: deleteAction,
|
||||
result: CommandResult.KeepOpen())
|
||||
{
|
||||
IsCritical = true,
|
||||
Icon = IconHelper.DeleteIcon,
|
||||
};
|
||||
contextMenu.Add(delete);
|
||||
|
||||
listItem.MoreCommands = contextMenu.ToArray();
|
||||
|
||||
return listItem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Helpers;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -17,6 +18,7 @@ internal sealed partial class OpenInTerminalCommand : InvokableCommand
|
||||
public OpenInTerminalCommand(string folder)
|
||||
{
|
||||
Name = Resources.bookmarks_open_in_terminal_name;
|
||||
Icon = IconHelper.CommandIcon;
|
||||
_folder = folder;
|
||||
}
|
||||
|
||||
@@ -35,7 +37,7 @@ internal sealed partial class OpenInTerminalCommand : InvokableCommand
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
ExtensionHost.LogMessage(new LogMessage() { Message = $"Error launching Windows Terminal: {ex.Message}" });
|
||||
}
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.Data;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Helpers;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks.Command;
|
||||
|
||||
public sealed partial class ShellCommand : InvokableCommand
|
||||
{
|
||||
public BookmarkData BookmarkData { get; }
|
||||
|
||||
public ShellCommand(BookmarkData data)
|
||||
{
|
||||
BookmarkData = data;
|
||||
Name = data.Name;
|
||||
Icon = IconHelper.CreateIcon(data.Bookmark, data.Type, false);
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
return ShellCommand.Invoke(BookmarkData.Type, BookmarkData.Bookmark);
|
||||
}
|
||||
|
||||
public static CommandResult Invoke(BookmarkType bookmarkType, string bookmarkValue)
|
||||
{
|
||||
if (bookmarkType == BookmarkType.Web)
|
||||
{
|
||||
var uri = OpenInShellHelper.GetUri(bookmarkValue);
|
||||
if (uri != null)
|
||||
{
|
||||
if (!OpenInShellHelper.OpenInShell(uri.ToString(), null, null, OpenInShellHelper.ShellRunAsType.None, false, out var errMsg))
|
||||
{
|
||||
ExtensionHost.LogMessage($"Failed to open {bookmarkValue} in shell. Ex: {errMsg}");
|
||||
return CommandResult.ShowToast(new ToastArgs() { Message = Resources.bookmarks_command_invoke_failed_message });
|
||||
}
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
else
|
||||
{
|
||||
return CommandResult.ShowToast(new ToastArgs() { Message = Resources.bookmarks_command_invoke_failed_message });
|
||||
}
|
||||
}
|
||||
|
||||
// if it's a file or folder bookmark, call them directly.
|
||||
if (bookmarkType == BookmarkType.File || bookmarkType == BookmarkType.Folder)
|
||||
{
|
||||
if (!OpenInShellHelper.OpenInShell(bookmarkValue, null, null, OpenInShellHelper.ShellRunAsType.None, false, out var errMsg))
|
||||
{
|
||||
ExtensionHost.LogMessage($"Failed to open {bookmarkValue} in shell. Ex: {errMsg}");
|
||||
return CommandResult.ShowToast(new ToastArgs() { Message = Resources.bookmarks_command_invoke_failed_message });
|
||||
}
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
|
||||
// We assume all command bookmarks will follow the same format.
|
||||
// For example: "python test.py" or "pwsh test.ps1"
|
||||
// So, we can split the command and get the first part as the command name.
|
||||
var splittedBookmarkValue = bookmarkValue.Split(" ");
|
||||
if (splittedBookmarkValue.Length == 0)
|
||||
{
|
||||
ExtensionHost.LogMessage($"Failed to open {bookmarkValue} in shell. Empty bookmark value.");
|
||||
return CommandResult.ShowToast(new ToastArgs() { Message = Resources.bookmarks_command_invoke_failed_message });
|
||||
}
|
||||
|
||||
if (splittedBookmarkValue.Length == 1)
|
||||
{
|
||||
// directly call. Because it maybe a command with no args. eg: haproxy.exe or cmd.exe
|
||||
if (!OpenInShellHelper.OpenInShell(splittedBookmarkValue[0], null, null, OpenInShellHelper.ShellRunAsType.None, false, out var errMsg))
|
||||
{
|
||||
ExtensionHost.LogMessage($"Failed to open {bookmarkValue} in shell. Ex: {errMsg}");
|
||||
return CommandResult.ShowToast(new ToastArgs() { Message = Resources.bookmarks_command_invoke_failed_message });
|
||||
}
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
|
||||
// args = without the first part and join with space
|
||||
var args = splittedBookmarkValue[1..];
|
||||
|
||||
if (!OpenInShellHelper.OpenInShell(splittedBookmarkValue[0], string.Join(" ", args), null, OpenInShellHelper.ShellRunAsType.None, false, out var errorMessage))
|
||||
{
|
||||
ExtensionHost.LogMessage($"Failed to open {bookmarkValue} in shell. Ex: {errorMessage}");
|
||||
return CommandResult.ShowToast(new ToastArgs() { Message = Resources.bookmarks_command_invoke_failed_message });
|
||||
}
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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 Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks.Helpers;
|
||||
|
||||
public static partial class BookmarkTypeHelper
|
||||
{
|
||||
/*
|
||||
* Summary:
|
||||
* If it's a valid uri, we assume it's a Web Link.
|
||||
* Otherwise, we check if it's a existing folder or file.
|
||||
* By default, we assume it's a command type.
|
||||
*/
|
||||
|
||||
public static BookmarkType GetBookmarkTypeFromValue(string bookmark)
|
||||
{
|
||||
// judge if the bookmark is a url
|
||||
var uri = OpenInShellHelper.GetUri(bookmark);
|
||||
if (uri?.Scheme == Uri.UriSchemeHttp || uri?.Scheme == Uri.UriSchemeHttps)
|
||||
{
|
||||
return BookmarkType.Web;
|
||||
}
|
||||
|
||||
// judge if the bookmark is a existing folder
|
||||
if (System.IO.Directory.Exists(bookmark))
|
||||
{
|
||||
return BookmarkType.Folder;
|
||||
}
|
||||
|
||||
// ok, fine. Actually, it's also have the possibility to be a shell command.
|
||||
// Such as 'test.cmd' or 'test.ps1'. Try to catch this case.
|
||||
if (System.IO.File.Exists(bookmark))
|
||||
{
|
||||
return BookmarkType.File;
|
||||
}
|
||||
|
||||
// by default. we assume it's a command type
|
||||
return BookmarkType.Command;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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 Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks.Helpers;
|
||||
|
||||
public static class IconHelper
|
||||
{
|
||||
public static IconInfo DeleteIcon { get; private set; } = new("\uE74D"); // Delete
|
||||
|
||||
public static IconInfo EditIcon { get; private set; } = new("\uE70F"); // Edit
|
||||
|
||||
public static IconInfo UrlIcon { get; private set; } = new("🔗"); // Web
|
||||
|
||||
public static IconInfo FolderIcon { get; private set; } = new("📁"); // Folder
|
||||
|
||||
public static IconInfo FileIcon { get; private set; } = new("📄"); // File
|
||||
|
||||
public static IconInfo CommandIcon { get; private set; } = new("\uE756"); // Command
|
||||
|
||||
public static IconInfo GetIconByType(BookmarkType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
BookmarkType.Web => UrlIcon,
|
||||
BookmarkType.Folder => FolderIcon,
|
||||
BookmarkType.File => FileIcon,
|
||||
BookmarkType.Command => CommandIcon,
|
||||
|
||||
_ => UrlIcon, // Default icon
|
||||
};
|
||||
}
|
||||
|
||||
public static IconInfo CreateIcon(string bookmark, BookmarkType bookmarkType, bool isPlaceholder)
|
||||
{
|
||||
// In some case, we want to use placeholder, but we can still get the favicon.
|
||||
// eg: "https://google.com?q={query}"
|
||||
if (bookmarkType == BookmarkType.Web)
|
||||
{
|
||||
// Get the base url up to the first placeholder
|
||||
var placeholderIndex = bookmark.IndexOf('{');
|
||||
var baseString = placeholderIndex > 0 ? bookmark.Substring(0, placeholderIndex) : bookmark;
|
||||
try
|
||||
{
|
||||
var uri = OpenInShellHelper.GetUri(baseString);
|
||||
if (uri != null)
|
||||
{
|
||||
var hostname = uri.Host;
|
||||
var faviconUrl = $"{uri.Scheme}://{hostname}/favicon.ico";
|
||||
return new IconInfo(faviconUrl);
|
||||
}
|
||||
}
|
||||
catch (UriFormatException ex)
|
||||
{
|
||||
ExtensionHost.LogMessage(new LogMessage() { Message = $"Create Icon failed. {ex}: {ex.Message}" });
|
||||
}
|
||||
}
|
||||
|
||||
if (isPlaceholder)
|
||||
{
|
||||
// If it's a placeholder bookmark, we don't need to get the icon.
|
||||
// Just use the default icon.
|
||||
return GetIconByType(bookmarkType);
|
||||
}
|
||||
|
||||
if (bookmarkType == BookmarkType.File || bookmarkType == BookmarkType.Folder)
|
||||
{
|
||||
// try to get the file icon first. If not, use the default file icon.
|
||||
try
|
||||
{
|
||||
// To be honest, I don't like to block thread.
|
||||
// We need to refactor in the future.
|
||||
// But now, it's ok. Only image file will trigger the async path.
|
||||
var stream = ThumbnailHelper.GetThumbnail(bookmark).Result;
|
||||
if (stream != null)
|
||||
{
|
||||
var data = new IconData(RandomAccessStreamReference.CreateFromStream(stream));
|
||||
return new IconInfo(data, data);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
ExtensionHost.LogMessage(new LogMessage() { Message = $"Create Icon failed. {bookmarkType}: {bookmark}" });
|
||||
}
|
||||
}
|
||||
|
||||
// If we can't get the icon, just use the default icon.
|
||||
return GetIconByType(bookmarkType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks.Helpers;
|
||||
|
||||
// TODO: ok fine, we have two OpenInShellHelper classes, one in CmdPal and one in System.
|
||||
// We should probably merge them into one. and move it to a common location.
|
||||
public static partial class OpenInShellHelper
|
||||
{
|
||||
public static bool OpenInShell(string path, string? arguments, string? workingDir, ShellRunAsType runAs, bool runWithHiddenWindow, out string errorMessage)
|
||||
{
|
||||
errorMessage = string.Empty;
|
||||
using var process = new Process();
|
||||
process.StartInfo.FileName = path;
|
||||
process.StartInfo.WorkingDirectory = string.IsNullOrWhiteSpace(workingDir) ? string.Empty : workingDir;
|
||||
process.StartInfo.Arguments = string.IsNullOrWhiteSpace(arguments) ? string.Empty : arguments;
|
||||
process.StartInfo.WindowStyle = runWithHiddenWindow ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal;
|
||||
process.StartInfo.UseShellExecute = true;
|
||||
|
||||
if (runAs == ShellRunAsType.Administrator)
|
||||
{
|
||||
process.StartInfo.Verb = "RunAs";
|
||||
}
|
||||
else if (runAs == ShellRunAsType.OtherUser)
|
||||
{
|
||||
process.StartInfo.Verb = "RunAsUser";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
return true;
|
||||
}
|
||||
catch (Win32Exception ex)
|
||||
{
|
||||
ExtensionHost.LogMessage(new LogMessage() { Message = $"Unable to open {path}: {ex.Message}" });
|
||||
errorMessage = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Uri? GetUri(string url)
|
||||
{
|
||||
Uri? uri;
|
||||
if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
|
||||
{
|
||||
if (!Uri.TryCreate("https://" + url, UriKind.Absolute, out uri))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
public enum ShellRunAsType
|
||||
{
|
||||
None,
|
||||
Administrator,
|
||||
OtherUser,
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks;
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
|
||||
public class BookmarkData
|
||||
{
|
||||
@@ -12,7 +12,8 @@ public class BookmarkData
|
||||
|
||||
public string Bookmark { get; set; } = string.Empty;
|
||||
|
||||
public string Type { get; set; } = string.Empty;
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<BookmarkType>))]
|
||||
public BookmarkType Type { get; set; } = BookmarkType.Web;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsPlaceholder => Bookmark.Contains('{') && Bookmark.Contains('}');
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
|
||||
public enum BookmarkType
|
||||
{
|
||||
Web,
|
||||
File,
|
||||
Folder,
|
||||
Command,
|
||||
}
|
||||
@@ -2,10 +2,10 @@
|
||||
// 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.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Helpers;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Foundation;
|
||||
@@ -23,6 +23,7 @@ internal sealed partial class AddBookmarkForm : FormContent
|
||||
_bookmark = bookmark;
|
||||
var name = _bookmark?.Name ?? string.Empty;
|
||||
var url = _bookmark?.Bookmark ?? string.Empty;
|
||||
|
||||
TemplateJson = $$"""
|
||||
{
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
@@ -33,25 +34,25 @@ internal sealed partial class AddBookmarkForm : FormContent
|
||||
"type": "Input.Text",
|
||||
"style": "text",
|
||||
"id": "name",
|
||||
"label": "{{Resources.bookmarks_form_name_label}}",
|
||||
"label": {{JsonSerializer.Serialize(Resources.bookmarks_form_name_label, BookmarkSerializationContext.Default.String)}},
|
||||
"value": {{JsonSerializer.Serialize(name, BookmarkSerializationContext.Default.String)}},
|
||||
"isRequired": true,
|
||||
"errorMessage": "{{Resources.bookmarks_form_name_required}}"
|
||||
"errorMessage": "{{JsonSerializer.Serialize(Resources.bookmarks_form_name_required, BookmarkSerializationContext.Default.String)}}"
|
||||
},
|
||||
{
|
||||
"type": "Input.Text",
|
||||
"style": "text",
|
||||
"id": "bookmark",
|
||||
"value": {{JsonSerializer.Serialize(url, BookmarkSerializationContext.Default.String)}},
|
||||
"label": "{{Resources.bookmarks_form_bookmark_label}}",
|
||||
"label": {{JsonSerializer.Serialize(Resources.bookmarks_form_bookmark_label, BookmarkSerializationContext.Default.String)}},
|
||||
"isRequired": true,
|
||||
"errorMessage": "{{Resources.bookmarks_form_bookmark_required}}"
|
||||
"errorMessage": "{{JsonSerializer.Serialize(Resources.bookmarks_form_bookmark_required, BookmarkSerializationContext.Default.String)}}"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"type": "Action.Submit",
|
||||
"title": "{{Resources.bookmarks_form_save}}",
|
||||
"title": {{JsonSerializer.Serialize(Resources.bookmarks_form_save, BookmarkSerializationContext.Default.String)}},
|
||||
"data": {
|
||||
"name": "name",
|
||||
"bookmark": "bookmark"
|
||||
@@ -73,33 +74,11 @@ internal sealed partial class AddBookmarkForm : FormContent
|
||||
// get the name and url out of the values
|
||||
var formName = formInput["name"] ?? string.Empty;
|
||||
var formBookmark = formInput["bookmark"] ?? string.Empty;
|
||||
var hasPlaceholder = formBookmark.ToString().Contains('{') && formBookmark.ToString().Contains('}');
|
||||
|
||||
// Determine the type of the bookmark
|
||||
string bookmarkType;
|
||||
|
||||
if (formBookmark.ToString().StartsWith("http://", StringComparison.OrdinalIgnoreCase) || formBookmark.ToString().StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
bookmarkType = "web";
|
||||
}
|
||||
else if (File.Exists(formBookmark.ToString()))
|
||||
{
|
||||
bookmarkType = "file";
|
||||
}
|
||||
else if (Directory.Exists(formBookmark.ToString()))
|
||||
{
|
||||
bookmarkType = "folder";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to web if we can't determine the type
|
||||
bookmarkType = "web";
|
||||
}
|
||||
|
||||
var updated = _bookmark ?? new BookmarkData();
|
||||
updated.Name = formName.ToString();
|
||||
updated.Bookmark = formBookmark.ToString();
|
||||
updated.Type = bookmarkType;
|
||||
updated.Type = BookmarkTypeHelper.GetBookmarkTypeFromValue(formBookmark.ToString());
|
||||
|
||||
AddedCommand?.Invoke(this, updated);
|
||||
return CommandResult.GoHome();
|
||||
@@ -2,6 +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 Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -7,12 +7,14 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.RegularExpressions;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Command;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks;
|
||||
|
||||
@@ -24,10 +26,14 @@ internal sealed partial class BookmarkPlaceholderForm : FormContent
|
||||
|
||||
private readonly string _bookmark = string.Empty;
|
||||
|
||||
private BookmarkType _bookmarkType;
|
||||
|
||||
// TODO pass in an array of placeholders
|
||||
public BookmarkPlaceholderForm(string name, string url, string type)
|
||||
public BookmarkPlaceholderForm(string name, string url, BookmarkType bookmarkType)
|
||||
{
|
||||
_bookmark = url;
|
||||
_bookmarkType = bookmarkType;
|
||||
|
||||
var r = new Regex(Regex.Escape("{") + "(.*?)" + Regex.Escape("}"));
|
||||
var matches = r.Matches(url);
|
||||
_placeholderNames = matches.Select(m => m.Groups[1].Value).ToList();
|
||||
@@ -38,10 +44,10 @@ internal sealed partial class BookmarkPlaceholderForm : FormContent
|
||||
{
|
||||
"type": "Input.Text",
|
||||
"style": "text",
|
||||
"id": "{{p}}",
|
||||
"label": "{{p}}",
|
||||
"id": "{{JsonSerializer.Serialize(p, BookmarkSerializationContext.Default.String)}}",
|
||||
"label": "{{JsonSerializer.Serialize(p, BookmarkSerializationContext.Default.String)}}",
|
||||
"isRequired": true,
|
||||
"errorMessage": "{{errorMessage}}"
|
||||
"errorMessage": "{{JsonSerializer.Serialize(errorMessage, BookmarkSerializationContext.Default.String)}}"
|
||||
}
|
||||
""";
|
||||
}).ToList();
|
||||
@@ -59,7 +65,7 @@ internal sealed partial class BookmarkPlaceholderForm : FormContent
|
||||
"actions": [
|
||||
{
|
||||
"type": "Action.Submit",
|
||||
"title": "{{Resources.bookmarks_form_open}}",
|
||||
"title": {{JsonSerializer.Serialize(Resources.bookmarks_form_open, BookmarkSerializationContext.Default.String)}},
|
||||
"data": {
|
||||
"placeholder": "placeholder"
|
||||
}
|
||||
@@ -90,15 +96,7 @@ internal sealed partial class BookmarkPlaceholderForm : FormContent
|
||||
|
||||
try
|
||||
{
|
||||
var uri = UrlCommand.GetUri(target);
|
||||
if (uri != null)
|
||||
{
|
||||
_ = Launcher.LaunchUriAsync(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// throw new UriFormatException("The provided URL is not valid.");
|
||||
}
|
||||
return ShellCommand.Invoke(_bookmarkType, target);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -2,6 +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 Microsoft.CmdPal.Ext.Bookmarks.Helpers;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
@@ -18,10 +20,10 @@ internal sealed partial class BookmarkPlaceholderPage : ContentPage
|
||||
{
|
||||
}
|
||||
|
||||
public BookmarkPlaceholderPage(string name, string url, string type)
|
||||
public BookmarkPlaceholderPage(string name, string url, BookmarkType type)
|
||||
{
|
||||
Name = name;
|
||||
Icon = new IconInfo(UrlCommand.IconFromUrl(url, type));
|
||||
Icon = IconHelper.CreateIcon(url, type, true);
|
||||
_bookmarkPlaceholder = new BookmarkPlaceholderForm(name, url, type);
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,15 @@ namespace Microsoft.CmdPal.Ext.Bookmarks.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unable to call command. Please check your configuration..
|
||||
/// </summary>
|
||||
public static string bookmarks_command_invoke_failed_message {
|
||||
get {
|
||||
return ResourceManager.GetString("bookmarks_command_invoke_failed_message", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Delete.
|
||||
/// </summary>
|
||||
|
||||
@@ -161,4 +161,7 @@
|
||||
<value>{0} is required</value>
|
||||
<comment>{0} will be replaced by a parameter name provided by the user</comment>
|
||||
</data>
|
||||
<data name="bookmarks_command_invoke_failed_message" xml:space="preserve">
|
||||
<value>Unable to call command. Please check your configuration.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1,99 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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 ManagedCommon;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Bookmarks;
|
||||
|
||||
public partial class UrlCommand : InvokableCommand
|
||||
{
|
||||
public string Type { get; }
|
||||
|
||||
public string Url { get; }
|
||||
|
||||
public UrlCommand(BookmarkData data)
|
||||
: this(data.Name, data.Bookmark, data.Type)
|
||||
{
|
||||
}
|
||||
|
||||
public UrlCommand(string name, string url, string type)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
Url = url;
|
||||
Icon = new IconInfo(IconFromUrl(Url, type));
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
var target = Url;
|
||||
try
|
||||
{
|
||||
var uri = GetUri(target);
|
||||
if (uri != null)
|
||||
{
|
||||
_ = Launcher.LaunchUriAsync(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// throw new UriFormatException("The provided URL is not valid.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
}
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
|
||||
internal static Uri? GetUri(string url)
|
||||
{
|
||||
Uri? uri;
|
||||
if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
|
||||
{
|
||||
if (!Uri.TryCreate("https://" + url, UriKind.Absolute, out uri))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
internal static string IconFromUrl(string url, string type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case "file":
|
||||
return "📄";
|
||||
case "folder":
|
||||
return "📁";
|
||||
case "web":
|
||||
default:
|
||||
// Get the base url up to the first placeholder
|
||||
var placeholderIndex = url.IndexOf('{');
|
||||
var baseString = placeholderIndex > 0 ? url.Substring(0, placeholderIndex) : url;
|
||||
try
|
||||
{
|
||||
var uri = GetUri(baseString);
|
||||
if (uri != null)
|
||||
{
|
||||
var hostname = uri.Host;
|
||||
var faviconUrl = $"{uri.Scheme}://{hostname}/favicon.ico";
|
||||
return faviconUrl;
|
||||
}
|
||||
}
|
||||
catch (UriFormatException ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
}
|
||||
|
||||
return "🔗";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user