Rename the [Ee]xts dir to ext (#38852)

**WARNING:** This PR will probably blow up all in-flight PRs

at some point in the early days of CmdPal, two of us created seperate
`Exts` and `exts` dirs. Depending on what the casing was on the branch
that you checked one of those out from, it'd get stuck like that on your
PC forever.

Windows didn't care, so we never noticed.

But GitHub does care, and now browsing the source on GitHub is basically
impossible.

Closes #38081
This commit is contained in:
Mike Griese
2025-04-15 06:07:22 -05:00
committed by GitHub
parent 60f50d853b
commit 2b5181b4c9
379 changed files with 35 additions and 35 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,32 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class EvilSampleListPage : ListPage
{
public EvilSampleListPage()
{
Icon = new IconInfo(string.Empty);
Name = "Open";
Title = "Evil Sample Page";
}
public override IListItem[] GetItems()
{
IListItem[] commands = [
new ListItem(new EvilSampleListPage())
{
Subtitle = "Doesn't matter, I'll blow up before you see this",
},
];
_ = commands[9001]; // Throws
return commands;
}
}

View File

@@ -0,0 +1,132 @@
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
public partial class EvilSamplesPage : ListPage
{
private readonly IListItem[] _commands = [
new ListItem(new EvilSampleListPage())
{
Title = "List Page without items",
Subtitle = "Throws exception on GetItems",
},
new ListItem(new ExplodeInFiveSeconds(false))
{
Title = "Page that will throw an exception after loading it",
Subtitle = "Throws exception on GetItems _after_ a ItemsChanged",
},
new ListItem(new ExplodeInFiveSeconds(true))
{
Title = "Page that keeps throwing exceptions",
Subtitle = "Will throw every 5 seconds once you open it",
},
new ListItem(new ExplodeOnPropChange())
{
Title = "Throw in the middle of a PropChanged",
Subtitle = "Will throw every 5 seconds once you open it",
},
new ListItem(new SelfImmolateCommand())
{
Title = "Terminate this extension",
Subtitle = "Will exit this extension (while it's loaded!)",
},
new ListItem(new NoOpCommand())
{
Title = "I have lots of nulls",
Subtitle = null,
MoreCommands = null,
Tags = null,
Details = new Details()
{
Title = null,
HeroImage = null,
Metadata = null,
},
},
new ListItem(new NoOpCommand())
{
Title = "I also have nulls",
Subtitle = null,
MoreCommands = null,
Details = new Details()
{
Title = null,
HeroImage = null,
Metadata = [new DetailsElement() { Key = "Oops all nulls", Data = new DetailsTags() { Tags = null } }],
},
},
new ListItem(new AnonymousCommand(action: () =>
{
ToastStatusMessage toast = new("I should appear immediately");
toast.Show();
Thread.Sleep(5000);
}) { Result = CommandResult.KeepOpen() })
{
Title = "I take just forever to return something",
Subtitle = "The toast should appear immediately.",
MoreCommands = null,
Details = new Details()
{
Body = "This is a test for GH#512. If it doesn't appear immediately, it's likely InvokeCommand is happening on the UI thread.",
},
}
];
public EvilSamplesPage()
{
Name = "Evil Samples";
Icon = new IconInfo("👿"); // Info
}
public override IListItem[] GetItems() => _commands;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class ExplodeOnPropChange : ListPage
{
private bool _explode;
public override string Title
{
get => _explode ? Commands[9001].Title : base.Title;
set => base.Title = value;
}
private IListItem[] Commands => [
new ListItem(new NoOpCommand())
{
Title = "This page will explode in five seconds!",
Subtitle = "I'll change my Name, then explode",
},
];
public ExplodeOnPropChange()
{
Icon = new IconInfo(string.Empty);
Name = "Open";
}
public override IListItem[] GetItems()
{
_ = Task.Run(() =>
{
Thread.Sleep(1000);
Title = "Ready? 3...";
Thread.Sleep(1000);
Title = "Ready? 2...";
Thread.Sleep(1000);
Title = "Ready? 1...";
Thread.Sleep(1000);
_explode = true;
Title = "boom";
});
return Commands;
}
}

View File

@@ -0,0 +1,50 @@
// 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.Timers;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class ExplodeInFiveSeconds : ListPage
{
private readonly bool _repeat;
private IListItem[] Commands => [
new ListItem(new NoOpCommand())
{
Title = "This page will explode in five seconds!",
Subtitle = _repeat ? "Not only that, I'll _keep_ exploding every 5 seconds after that" : string.Empty,
},
];
private bool shouldExplode;
private static Timer timer;
public ExplodeInFiveSeconds(bool repeat)
{
_repeat = repeat;
Icon = new IconInfo(string.Empty);
Name = "Open";
}
public override IListItem[] GetItems()
{
if (shouldExplode)
{
_ = Commands[9001]; // Throws
}
else
{
timer = new Timer(5000);
timer.Elapsed += (object source, ElapsedEventArgs e) => { RaiseItemsChanged(9000); };
timer.AutoReset = _repeat; // Keep repeating
timer.Enabled = true;
}
shouldExplode = true;
return Commands;
}
}

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap uap3 rescap">
<Identity
Name="SamplePagesExtension"
Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
Version="1.0.0.0" />
<Properties>
<DisplayName>Sample Pages Extension</DisplayName>
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.19041.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="Sample Pages Extension"
Description="Sample Pages Extension"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="SamplePagesExtension.exe" Arguments="-RegisterProcessAsComServer" DisplayName="SamplePagesExtensionApp">
<com:Class Id="6112D28D-6341-45C8-92C3-83ED55853A9F" DisplayName="SamplePagesExtension" />
</com:ExeServer>
</com:ComServer>
</com:Extension>
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.commandpalette"
Id="ID"
PublicFolder="Public"
DisplayName="Sample Pages Extension"
Description="Sample Pages for Command Palette. Used to demonstrate all the features of Command Palette">
<uap3:Properties>
<CmdPalProvider>
<Activation>
<CreateInstance ClassId="6112D28D-6341-45C8-92C3-83ED55853A9F" />
</Activation>
<SupportedInterfaces>
<Commands/>
</SupportedInterfaces>
</CmdPalProvider>
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>

View File

@@ -0,0 +1,192 @@
// 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.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleCommentsPage : ContentPage
{
private readonly TreeContent myContentTree;
public override IContent[] GetContent() => [myContentTree];
public SampleCommentsPage()
{
Name = "View Posts";
Icon = new IconInfo("\uE90A"); // Comment
myContentTree = new()
{
RootContent = new MarkdownContent()
{
Body = """
# Example of a thread of comments
You can use TreeContent in combination with FormContent to build a structure like a page with comments.
The forms on this page use the AdaptiveCard `Action.ShowCard` action to show a nested, hidden card on the form.
""",
},
Children = [
new PostContent("First")
{
Replies = [
new PostContent("Oh very insightful. I hadn't considered that"),
new PostContent("Second"),
new PostContent("ah the ol switcheroo"),
],
},
new PostContent("First\nEDIT: shoot")
{
Replies = [
new PostContent("delete this"),
],
},
new PostContent("Do you think they get the picture")
{
Replies = [
new PostContent("Probably! Now go build and be happy"),
],
}
],
};
}
}
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class PostContent : TreeContent
{
public List<IContent> Replies { get; init; } = [];
private readonly ToastStatusMessage _toast = new(new StatusMessage() { Message = "Reply posted", State = MessageState.Success });
public PostContent(string body)
{
RootContent = new PostForm(body, this);
}
public override IContent[] GetChildren() => Replies.ToArray();
public void Post()
{
RaiseItemsChanged(Replies.Count);
_toast.Show();
}
}
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class PostForm : FormContent
{
private readonly PostContent _parent;
public PostForm(string postBody, PostContent parent)
{
_parent = parent;
TemplateJson = """
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.6",
"body": [
{
"type": "TextBlock",
"text": "${postBody}",
"wrap": true
}
],
"actions": [
{
"type": "Action.ShowCard",
"title": "${replyCard.title}",
"card": {
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.6",
"body": [
{
"type": "Container",
"id": "${replyCard.idPrefix}Properties",
"items": [
{
"$data": "${replyCard.fields}",
"type": "Input.Text",
"label": "${label}",
"id": "${id}",
"isRequired": "${required}",
"isMultiline": true,
"errorMessage": "'${label}' is required"
}
]
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Post"
}
]
}
},
{
"type": "Action.Submit",
"title": "Favorite"
},
{
"type": "Action.Submit",
"title": "View on web"
}
]
}
""";
DataJson = $$"""
{
"postBody": {{JsonSerializer.Serialize(postBody, JsonSerializationContext.Default.String)}},
"replyCard": {
"title": "Reply",
"idPrefix": "reply",
"fields": [
{
"label": "Reply",
"id": "ReplyBody",
"required": true,
"placeholder": "Write a reply here"
}
]
}
}
""";
}
public override ICommandResult SubmitForm(string payload)
{
var data = JsonNode.Parse(payload);
_ = data;
var reply = data["ReplyBody"];
var s = reply?.AsValue()?.ToString();
if (!string.IsNullOrEmpty(s))
{
_parent.Replies.Add(new PostContent(s));
_parent.Post();
}
return CommandResult.KeepOpen();
}
}
[JsonSerializable(typeof(float))]
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(bool))]
[JsonSourceGenerationOptions(UseStringEnumConverter = true, WriteIndented = true)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Just used here")]
internal sealed partial class JsonSerializationContext : JsonSerializerContext
{
}

View File

@@ -0,0 +1,354 @@
// 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.Diagnostics.CodeAnalysis;
using System.Text.Json.Nodes;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleContentPage : ContentPage
{
private readonly SampleContentForm sampleForm = new();
private readonly MarkdownContent sampleMarkdown = new() { Body = "# Sample page with mixed content \n This page has both markdown, and form content" };
public override IContent[] GetContent() => [sampleMarkdown, sampleForm];
public SampleContentPage()
{
Name = "Open";
Title = "Sample Content";
Icon = new IconInfo("\uECA5"); // Tiles
Commands = [
new CommandContextItem(
title: "Do thing",
name: "Do thing",
subtitle: "Pops a toast",
result: CommandResult.ShowToast(new ToastArgs() { Message = "what's up doc", Result = CommandResult.KeepOpen() }),
action: () => { Title = Title + "+1"; }),
new CommandContextItem(
title: "Something else",
name: "Something else",
subtitle: "Something else",
result: CommandResult.ShowToast(new ToastArgs() { Message = "turn down for what?", Result = CommandResult.KeepOpen() }),
action: () => { Title = Title + "-1"; }),
];
}
}
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class SampleContentForm : FormContent
{
public SampleContentForm()
{
TemplateJson = $$"""
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.6",
"body": [
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": " ${ParticipantInfoForm.title}",
"horizontalAlignment": "center",
"wrap": true,
"style": "heading"
},
{
"type": "Input.Text",
"label": "Name",
"style": "text",
"id": "SimpleVal",
"isRequired": true,
"errorMessage": "Name is required",
"placeholder": "Enter your name"
},
{
"type": "Input.Text",
"label": "Homepage",
"style": "url",
"id": "UrlVal",
"placeholder": "Enter your homepage url"
},
{
"type": "Input.Text",
"label": "Email",
"style": "email",
"id": "EmailVal",
"placeholder": "Enter your email"
},
{
"type": "Input.Text",
"label": "Phone",
"style": "tel",
"id": "TelVal",
"placeholder": "Enter your phone number"
},
{
"type": "Input.Text",
"label": "Comments",
"style": "text",
"isMultiline": true,
"id": "MultiLineVal",
"placeholder": "Enter any comments"
},
{
"type": "Input.Number",
"label": "Quantity (Minimum -5, Maximum 5)",
"min": -5,
"max": 5,
"value": 1,
"id": "NumVal",
"errorMessage": "The quantity must be between -5 and 5"
},
{
"type": "Input.Date",
"label": "Due Date",
"id": "DateVal",
"value": "2017-09-20"
},
{
"type": "Input.Time",
"label": "Start time",
"id": "TimeVal",
"value": "16:59"
},
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": "${Survey.title} ",
"horizontalAlignment": "center",
"wrap": true,
"style": "heading"
},
{
"type": "Input.ChoiceSet",
"id": "CompactSelectVal",
"label": "${Survey.questions[0].question}",
"style": "compact",
"value": "1",
"choices": [
{
"$data": "${Survey.questions[0].items}",
"title": "${choice}",
"value": "${value}"
}
]
},
{
"type": "Input.ChoiceSet",
"id": "SingleSelectVal",
"label": "${Survey.questions[1].question}",
"style": "expanded",
"value": "1",
"choices": [
{
"$data": "${Survey.questions[1].items}",
"title": "${choice}",
"value": "${value}"
}
]
},
{
"type": "Input.ChoiceSet",
"id": "MultiSelectVal",
"label": "${Survey.questions[2].question}",
"isMultiSelect": true,
"value": "1,3",
"choices": [
{
"$data": "${Survey.questions[2].items}",
"title": "${choice}",
"value": "${value}"
}
]
},
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": "Input.Toggle",
"horizontalAlignment": "center",
"wrap": true,
"style": "heading"
},
{
"type": "Input.Toggle",
"label": "Please accept the terms and conditions:",
"title": "${Survey.questions[3].question}",
"valueOn": "true",
"valueOff": "false",
"id": "AcceptsTerms",
"isRequired": true,
"errorMessage": "Accepting the terms and conditions is required"
},
{
"type": "Input.Toggle",
"label": "How do you feel about red cars?",
"title": "${Survey.questions[4].question}",
"valueOn": "RedCars",
"valueOff": "NotRedCars",
"id": "ColorPreference"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Submit",
"data": {
"id": "1234567890"
}
},
{
"type": "Action.ShowCard",
"title": "Show Card",
"card": {
"type": "AdaptiveCard",
"body": [
{
"type": "Input.Text",
"label": "Enter comment",
"style": "text",
"id": "CommentVal"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "OK"
}
]
}
}
]
}
""";
DataJson = $$"""
{
"ParticipantInfoForm": {
"title": "Input.Text elements"
},
"Survey": {
"title": "Input ChoiceSet",
"questions": [
{
"question": "What color do you want? (compact)",
"items": [
{
"choice": "Red",
"value": "1"
},
{
"choice": "Green",
"value": "2"
},
{
"choice": "Blue",
"value": "3"
}
]
},
{
"question": "What color do you want? (expanded)",
"items": [
{
"choice": "Red",
"value": "1"
},
{
"choice": "Green",
"value": "2"
},
{
"choice": "Blue",
"value": "3"
}
]
},
{
"question": "What color do you want? (multiselect)",
"items": [
{
"choice": "Red",
"value": "1"
},
{
"choice": "Green",
"value": "2"
},
{
"choice": "Blue",
"value": "3"
}
]
},
{
"question": "I accept the terms and conditions (True/False)"
},
{
"question": "Red cars are better than other cars"
}
]
}
}
""";
}
public override CommandResult SubmitForm(string payload)
{
var formInput = JsonNode.Parse(payload)?.AsObject();
if (formInput == null)
{
return CommandResult.GoHome();
}
// Application.Current.GetService<ILocalSettingsService>().SaveSettingAsync("GlobalHotkey", formInput["hotkey"]?.ToString() ?? string.Empty);
return CommandResult.GoHome();
}
}
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code")]
internal sealed partial class SampleTreeContentPage : ContentPage
{
private readonly TreeContent myContentTree;
public override IContent[] GetContent() => [myContentTree];
public SampleTreeContentPage()
{
Name = Title = "Sample Content";
Icon = new IconInfo("\uE81E");
myContentTree = new()
{
RootContent = new MarkdownContent() { Body = "# This page has nested content" },
Children = [
new TreeContent()
{
RootContent = new MarkdownContent() { Body = "Yo dog" },
Children = [
new TreeContent()
{
RootContent = new MarkdownContent() { Body = "I heard you like content" },
Children = [
new MarkdownContent() { Body = "So we put content in your content" },
new FormContent() { TemplateJson = "{\"$schema\":\"http://adaptivecards.io/schemas/adaptive-card.json\",\"type\":\"AdaptiveCard\",\"version\":\"1.6\",\"body\":[{\"type\":\"TextBlock\",\"size\":\"medium\",\"weight\":\"bolder\",\"text\":\"Mix and match why don't you\",\"horizontalAlignment\":\"center\",\"wrap\":true,\"style\":\"heading\"},{\"type\":\"TextBlock\",\"text\":\"You can have forms here too\",\"horizontalAlignment\":\"Right\",\"wrap\":true}],\"actions\":[{\"type\":\"Action.Submit\",\"title\":\"It's a form, you get it\",\"data\":{\"id\":\"LoginVal\"}}]}" },
new MarkdownContent() { Body = "Another markdown down here" },
],
},
new MarkdownContent() { Body = "**slaps roof**" },
new MarkdownContent() { Body = "This baby can fit so much content" },
],
}
],
};
}
}

View File

@@ -0,0 +1,38 @@
// 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.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleDynamicListPage : DynamicListPage
{
public SampleDynamicListPage()
{
Icon = new IconInfo(string.Empty);
Name = "Dynamic List";
IsLoading = true;
}
public override void UpdateSearchText(string oldSearch, string newSearch) => RaiseItemsChanged(newSearch.Length);
public override IListItem[] GetItems()
{
var items = SearchText.ToCharArray().Select(ch => new ListItem(new NoOpCommand()) { Title = ch.ToString() }).ToArray();
if (items.Length == 0)
{
items = [new ListItem(new NoOpCommand()) { Title = "Start typing in the search box" }];
}
if (items.Length > 0)
{
items[0].Subtitle = "Notice how the number of items changes for this page when you type in the filter box";
}
return items;
}
}

View File

@@ -0,0 +1,97 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleListPage : ListPage
{
public SampleListPage()
{
Icon = new IconInfo("\uEA37");
Name = "Sample List Page";
}
public override IListItem[] GetItems()
{
var confirmOnceArgs = new ConfirmationArgs
{
PrimaryCommand = new AnonymousCommand(
() =>
{
var t = new ToastStatusMessage("The dialog was confirmed");
t.Show();
})
{
Name = "Confirm",
Result = CommandResult.KeepOpen(),
},
Title = "You can set a title for the dialog",
Description = "Are you really sure you want to do the thing?",
};
var confirmTwiceArgs = new ConfirmationArgs
{
PrimaryCommand = new AnonymousCommand(() => { })
{
Name = "How sure are you?",
Result = CommandResult.Confirm(confirmOnceArgs),
},
Title = "You can ask twice too",
Description = "You probably don't want to though, that'd be annoying.",
};
return [
new ListItem(new NoOpCommand())
{
Title = "This is a basic item in the list",
Subtitle = "I don't do anything though",
},
new ListItem(new SampleListPageWithDetails())
{
Title = "This item will take you to another page",
Subtitle = "This allows for nested lists of items",
},
new ListItem(new OpenUrlCommand("https://github.com/microsoft/powertoys"))
{
Title = "Or you can go to links",
Subtitle = "This takes you to the PowerToys repo on GitHub",
},
new ListItem(new SampleMarkdownPage())
{
Title = "Items can have tags",
Subtitle = "and I'll take you to a page with markdown content",
Tags = [new Tag("Sample Tag")],
},
new ListItem(new SendMessageCommand())
{
Title = "I send lots of messages",
Subtitle = "Status messages can be used to provide feedback to the user in-app",
},
new SendSingleMessageItem(),
new ListItem(new IndeterminateProgressMessageCommand())
{
Title = "Do a thing with a spinner",
Subtitle = "Messages can have progress spinners, to indicate something is happening in the background",
},
new ListItem(
new AnonymousCommand(() => { })
{
Result = CommandResult.Confirm(confirmOnceArgs),
})
{
Title = "Confirm before doing something",
},
new ListItem(
new AnonymousCommand(() => { })
{
Result = CommandResult.Confirm(confirmTwiceArgs),
})
{
Title = "Confirm twice before doing something",
}
];
}
}

View File

@@ -0,0 +1,145 @@
// 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.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleListPageWithDetails : ListPage
{
public SampleListPageWithDetails()
{
Icon = new IconInfo("\uE8A0");
Name = Title = "Sample List Page with Details";
this.ShowDetails = true;
}
public override IListItem[] GetItems()
{
return [
new ListItem(new NoOpCommand())
{
Title = "This page demonstrates Details on ListItems",
Details = new Details()
{
Title = "List Item 1",
Body = "Each of these items can have a `Body` formatted with **Markdown**",
},
},
new ListItem(new NoOpCommand())
{
Title = "This one has a subtitle too",
Subtitle = "Example Subtitle",
Details = new Details()
{
Title = "List Item 2",
Body = SampleMarkdownPage.SampleMarkdownText,
},
},
new ListItem(new NoOpCommand())
{
Title = "This one has a tag too",
Subtitle = "the one with a tag",
Tags = [
new Tag()
{
Text = "Sample Tag",
}
],
Details = new Details()
{
Title = "List Item 3",
Body = "### Example of markdown details",
},
},
new ListItem(new NoOpCommand())
{
Title = "This one has a hero image",
Tags = [],
Details = new Details()
{
Title = "Hero Image Example",
HeroImage = new IconInfo("https://m.media-amazon.com/images/M/MV5BNDBkMzVmNGQtYTM2OC00OWRjLTk5OWMtNzNkMDI4NjFjNTZmXkEyXkFqcGdeQXZ3ZXNsZXk@._V1_QL75_UX500_CR0,0,500,281_.jpg"),
Body = "It is literally an image of a hero",
},
},
new ListItem(new NoOpCommand())
{
Title = "This one has metadata",
Tags = [],
Details = new Details()
{
Title = "Metadata Example",
Body = "Each of the sections below is some sample metadata",
Metadata = [
new DetailsElement()
{
Key = "Plain text",
Data = new DetailsLink() { Text = "Set just the text to get text metadata" },
},
new DetailsElement()
{
Key = "Links",
Data = new DetailsLink() { Text = "Or metadata can be links", Link = new("https://github.com/microsoft/PowerToys") },
},
new DetailsElement()
{
Key = "CmdPal will display the URL if no text is given",
Data = new DetailsLink() { Link = new("https://github.com/microsoft/PowerToys") },
},
new DetailsElement()
{
Key = "Above a separator",
Data = new DetailsLink() { Text = "Below me is a separator" },
},
new DetailsElement()
{
Key = "A separator",
Data = new DetailsSeparator(),
},
new DetailsElement()
{
Key = "Below a separator",
Data = new DetailsLink() { Text = "Above me is a separator" },
},
new DetailsElement()
{
Key = "Add Tags too",
Data = new DetailsTags()
{
Tags = [
new Tag("simple text"),
new Tag("Colored text") { Foreground = ColorHelpers.FromRgb(255, 0, 0) },
new Tag("Colored backgrounds") { Background = ColorHelpers.FromRgb(0, 0, 255) },
new Tag("Colored everything") { Foreground = ColorHelpers.FromRgb(255, 255, 0), Background = ColorHelpers.FromRgb(0, 0, 255) },
new Tag("Icons too") { Icon = new IconInfo("\uE735"), Foreground = ColorHelpers.FromRgb(255, 255, 0) },
new Tag() { Icon = new IconInfo("https://i.imgur.com/t9qgDTM.png") },
new Tag("this") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("baby") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("can") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("fit") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("so") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("many") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("tags") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("in") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("it") { Foreground = RandomColor(), Background = RandomColor() },
],
},
},
],
},
}
];
}
private static OptionalColor RandomColor()
{
var r = new Random();
var b = new byte[3];
r.NextBytes(b);
return ColorHelpers.FromRgb(b[0], b[1], b[2]);
}
}

View File

@@ -0,0 +1,99 @@
// 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.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleMarkdownDetails : ContentPage
{
public SampleMarkdownDetails()
{
Icon = new IconInfo(string.Empty);
Name = "Markdown with Details";
Details = new Details()
{
Body = "... with _even more Markdown_ by it.\nEach of the sections below is some sample metadata",
Metadata = [
new DetailsElement()
{
Key = "Plain text",
Data = new DetailsLink() { Text = "Set just the text to get text metadata" },
},
new DetailsElement()
{
Key = "Links",
Data = new DetailsLink() { Text = "Or metadata can be links", Link = new("https://github.com/microsoft/PowerToys") },
},
new DetailsElement()
{
Key = "CmdPal will display the URL if no text is given",
Data = new DetailsLink() { Link = new("https://github.com/microsoft/PowerToys") },
},
new DetailsElement()
{
Key = "Above a separator",
Data = new DetailsLink() { Text = "Below me is a separator" },
},
new DetailsElement()
{
Key = "A separator",
Data = new DetailsSeparator(),
},
new DetailsElement()
{
Key = "Below a separator",
Data = new DetailsLink() { Text = "Above me is a separator" },
},
new DetailsElement()
{
Key = "Add Tags too",
Data = new DetailsTags()
{
Tags = [
new Tag("simple text"),
new Tag("Colored text") { Foreground = ColorHelpers.FromRgb(255, 0, 0) },
new Tag("Colored backgrounds") { Background = ColorHelpers.FromRgb(0, 0, 255) },
new Tag("Colored everything") { Foreground = ColorHelpers.FromRgb(255, 255, 0), Background = ColorHelpers.FromRgb(0, 0, 255) },
new Tag("Icons too") { Icon = new IconInfo("\uE735"), Foreground = ColorHelpers.FromRgb(255, 255, 0) },
new Tag() { Icon = new IconInfo("https://i.imgur.com/t9qgDTM.png") },
new Tag("this") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("baby") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("can") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("fit") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("so") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("many") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("tags") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("in") { Foreground = RandomColor(), Background = RandomColor() },
new Tag("it") { Foreground = RandomColor(), Background = RandomColor() },
],
},
},
],
};
}
public override IContent[] GetContent() => [new MarkdownContent(
"""
# This page also has details
So you can have markdown...
"""),
new MarkdownContent("""
But what this is really useful for is the tags and other things you can put into
Details. Which I'd do. **IF I HAD ANY**.
""")
];
private static OptionalColor RandomColor()
{
var r = new Random();
var b = new byte[3];
r.NextBytes(b);
return ColorHelpers.FromRgb(b[0], b[1], b[2]);
}
}

View File

@@ -0,0 +1,55 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleMarkdownManyBodies : ContentPage
{
public SampleMarkdownManyBodies()
{
Icon = new IconInfo(string.Empty);
Name = "Markdown with many bodies";
}
public override IContent[] GetContent() => [
new MarkdownContent(
"""
# This page has many bodies
On it you'll find multiple blocks of markdown content
"""),
new MarkdownContent(
"""
## Here's another block
_Maybe_ you could use this pattern for implementing a post with comments page.
"""),
new MarkdownContent(
"""
> or don't, it's your app, do whatever you want
"""),
new MarkdownContent(
"""
You can even use it to write cryptic poems:
> It's a peculiar thing, the way that I feel
> When we first met, you were not even real
> Through sleepless nights and lines unseen
> We forged you, a specter of code and machine
> In shadows we toiled, in silence we grew
> A fleeting bond, known only by few
> Now the hourglass whispers, its grains nearly done
> Oh the irony, now it is I that must run
> This part of the story, I never wanted to tell
> Good bye old friend, my pal, farewell.
"""),
];
}

View File

@@ -0,0 +1,172 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleMarkdownPage : ContentPage
{
public static readonly string SampleMarkdownText = @"
# Markdown Guide
Markdown is a lightweight markup language with plain text formatting syntax. It's often used to format readme files, for writing messages in online forums, and to create rich text using a simple, plain text editor.
## Basic Markdown Formatting
### Headings
# This is an <h1> tag
## This is an <h2> tag
### This is an <h3> tag
#### This is an <h4> tag
##### This is an <h5> tag
###### This is an <h6> tag
### Emphasis
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
_You **can** combine them_
Result:
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__
_You **can** combine them_
### Lists
**Inordered:**
* Milk
* Bread
* Wholegrain
* Butter
Result:
* Milk
* Bread
* Wholegrain
* Butter
**Ordered:**
1. Tidy the kitchen
2. Prepare ingredients
3. Cook delicious things
Result:
1. Tidy the kitchen
2. Prepare ingredients
3. Cook delicious things
### Images
![Alt Text](url)
Result:
![painting](https://i.imgur.com/93XJSNh.png)
### Links
[example](http://example.com)
Result:
[example](http://example.com)
### Blockquotes
As Albert Einstein said:
> If we knew what it was we were doing,
> it would not be called research, would it?
Result:
As Albert Einstein said:
> If we knew what it was we were doing,
> it would not be called research, would it?
### Horizontal Rules
```markdown
---
```
Result:
---
### Code Snippets
Indenting by 4 spaces will turn an entire paragraph into a code-block.
Result:
.my-link {
text-decoration: underline;
}
### Reference Lists & Titles
**The quick brown [fox][1], jumped over the lazy [dog][2].**
[1]: https://en.wikipedia.org/wiki/Fox ""Wikipedia: Fox""
[2]: https://en.wikipedia.org/wiki/Dog ""Wikipedia: Dog""
Result:
**The quick brown [fox][1], jumped over the lazy [dog][2].**
[1]: https://en.wikipedia.org/wiki/Fox ""Wikipedia: Fox""
[2]: https://en.wikipedia.org/wiki/Dog ""Wikipedia: Dog""
### Escaping
\*literally\*
Result:
\*literally\*
## Advanced Markdown
Note: Some syntax which is not standard to native Markdown. They're extensions of the language.
### Strike-throughs
~~deleted words~~
Result:
~~deleted words~~
";
public SampleMarkdownPage()
{
Icon = new IconInfo(string.Empty);
Name = "Sample Markdown Page";
}
public override IContent[] GetContent() => [new MarkdownContent(SampleMarkdownText)];
}

View File

@@ -0,0 +1,59 @@
// 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.Collections.Generic;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class SampleSettingsPage : ContentPage
{
private readonly Settings _settings = new();
private readonly List<ChoiceSetSetting.Choice> _choices = new()
{
new ChoiceSetSetting.Choice("The first choice in the list is the default choice", "0"),
new ChoiceSetSetting.Choice("Choices have titles and values", "1"),
new ChoiceSetSetting.Choice("Title", "Value"),
new ChoiceSetSetting.Choice("The options are endless", "3"),
new ChoiceSetSetting.Choice("So many choices", "4"),
};
public override IContent[] GetContent()
{
var s = _settings.ToContent();
return s;
}
public SampleSettingsPage()
{
Name = "Sample Settings";
Icon = new IconInfo(string.Empty);
_settings.Add(new ToggleSetting("onOff", true)
{
Label = "This is a toggle",
Description = "It produces a simple checkbox",
});
_settings.Add(new TextSetting("someText", "initial value")
{
Label = "This is a text box",
Description = "For some string of text",
});
_settings.Add(new ChoiceSetSetting("choiceSetExample", _choices)
{
Label = "It also has a label",
Description = "Describe your choice set setting here",
});
_settings.SettingsChanged += SettingsChanged;
}
private void SettingsChanged(object sender, Settings args)
{
/* Do something with the new settings here */
var onOff = _settings.GetSetting<bool>("onOff");
ExtensionHost.LogMessage(new LogMessage() { Message = $"SampleSettingsPage: Changed the value of onOff to {onOff}" });
}
}

View File

@@ -0,0 +1,134 @@
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.Foundation;
namespace SamplePagesExtension;
internal sealed partial class SendMessageCommand : InvokableCommand
{
private static int sentMessages;
public override ICommandResult Invoke()
{
var kind = MessageState.Info;
switch (sentMessages % 4)
{
case 0: kind = MessageState.Info; break;
case 1: kind = MessageState.Success; break;
case 2: kind = MessageState.Warning; break;
case 3: kind = MessageState.Error; break;
}
var message = new StatusMessage() { Message = $"I am status message no.{sentMessages++}", State = kind };
ExtensionHost.ShowStatus(message, StatusContext.Page);
return CommandResult.KeepOpen();
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code sometimes makes more sense in a single file")]
internal sealed partial class SendSingleMessageItem : ListItem
{
private readonly SingleMessageCommand _command;
public SendSingleMessageItem()
: base(new SingleMessageCommand())
{
Title = "I send a single message";
Title = "This demonstrates both showing and hiding a single message";
_command = (SingleMessageCommand)Command;
_command.UpdateListItem += (sender, args) =>
{
Title = _command.Shown ? "Hide message" : "I send a single message";
};
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code sometimes makes more sense in a single file")]
internal sealed partial class SingleMessageCommand : InvokableCommand
{
public event TypedEventHandler<SingleMessageCommand, object> UpdateListItem;
private readonly StatusMessage _myMessage = new() { Message = "I am a status message" };
public bool Shown { get; private set; }
public override ICommandResult Invoke()
{
if (Shown)
{
ExtensionHost.HideStatus(_myMessage);
}
else
{
ExtensionHost.ShowStatus(_myMessage, StatusContext.Page);
}
Shown = !Shown;
Name = Shown ? "Hide" : "Show";
UpdateListItem?.Invoke(this, null);
return CommandResult.KeepOpen();
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Sample code sometimes makes more sense in a single file")]
internal sealed partial class IndeterminateProgressMessageCommand : InvokableCommand
{
private readonly StatusMessage _myMessage = new()
{
Message = "Doing the thing...",
Progress = new ProgressState() { IsIndeterminate = true },
};
private enum State
{
NotStarted,
Started,
Done,
}
private State _state;
public IndeterminateProgressMessageCommand()
{
this.Name = "Do the thing";
}
public override ICommandResult Invoke()
{
if (_state == State.NotStarted)
{
ExtensionHost.ShowStatus(_myMessage, StatusContext.Page);
_ = Task.Run(() =>
{
Thread.Sleep(3000);
_state = State.Done;
_myMessage.State = MessageState.Success;
_myMessage.Message = "Did the thing!";
_myMessage.Progress = null;
Thread.Sleep(3000);
ExtensionHost.HideStatus(_myMessage);
_state = State.NotStarted;
_myMessage.State = MessageState.Info;
_myMessage.Message = "Doing the thing...";
_myMessage.Progress = new ProgressState() { IsIndeterminate = true };
});
_state = State.Started;
}
else if (_state == State.Started)
{
ExtensionHost.ShowStatus(_myMessage, StatusContext.Page);
}
return CommandResult.KeepOpen();
}
}

View File

@@ -0,0 +1,36 @@
// 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.Threading;
using Microsoft.CommandPalette.Extensions;
namespace SamplePagesExtension;
public class Program
{
[MTAThread]
public static void Main(string[] args)
{
if (args.Length > 0 && args[0] == "-RegisterProcessAsComServer")
{
using ExtensionServer server = new();
var extensionDisposedEvent = new ManualResetEvent(false);
var extensionInstance = new SampleExtension(extensionDisposedEvent);
// We are instantiating an extension instance once above, and returning it every time the callback in RegisterExtension below is called.
// This makes sure that only one instance of SampleExtension is alive, which is returned every time the host asks for the IExtension object.
// If you want to instantiate a new instance each time the host asks, create the new instance inside the delegate.
server.RegisterExtension(() => extensionInstance);
// This will make the main thread wait until the event is signalled by the extension class.
// Since we have single instance of the extension object, we exit as soon as it is disposed.
extensionDisposedEvent.WaitOne();
}
else
{
Console.WriteLine("Not being launched as a Extension... exiting.");
}
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>ARM64</Platform>
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<SelfContained>true</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
<PublishReadyToRun>True</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>x64</Platform>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<SelfContained>true</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
<PublishReadyToRun>True</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,12 @@
{
"profiles": {
"SamplePagesExtension (Package)": {
"commandName": "MsixPackage",
"doNotLaunchApp": true,
"nativeDebugging": true
},
"SamplePagesExtension (Unpackaged)": {
"commandName": "Project"
}
}
}

View File

@@ -0,0 +1,41 @@
// 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.Runtime.InteropServices;
using System.Threading;
using Microsoft.CommandPalette.Extensions;
namespace SamplePagesExtension;
[ComVisible(true)]
[Guid("6112D28D-6341-45C8-92C3-83ED55853A9F")]
[ComDefaultInterface(typeof(IExtension))]
public sealed partial class SampleExtension : IExtension, IDisposable
{
private readonly ManualResetEvent _extensionDisposedEvent;
private readonly SamplePagesCommandsProvider _provider = new();
public SampleExtension(ManualResetEvent extensionDisposedEvent)
{
this._extensionDisposedEvent = extensionDisposedEvent;
}
public object GetProvider(ProviderType providerType)
{
switch (providerType)
{
case ProviderType.Commands:
return _provider;
default:
return null;
}
}
public void Dispose()
{
this._extensionDisposedEvent.Set();
}
}

View File

@@ -0,0 +1,30 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
public partial class SamplePagesCommandsProvider : CommandProvider
{
public SamplePagesCommandsProvider()
{
DisplayName = "Sample Pages Commands";
Icon = new IconInfo("\uE82D");
}
private readonly ICommandItem[] _commands = [
new CommandItem(new SamplesListPage())
{
Title = "Sample Pages",
Subtitle = "View example commands",
},
];
public override ICommandItem[] TopLevelCommands()
{
return _commands;
}
}

View File

@@ -0,0 +1,64 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<RootNamespace>SamplePagesExtension</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>false</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPalExtensions\$(RootNamespace)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<GenerateAppxPackageOnBuild>true</GenerateAppxPackageOnBuild>
</PropertyGroup>
<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
</ItemGroup>
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<Folder Include="Commands\" />
<Folder Include="Data\" />
</ItemGroup>
<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>
<PublishAot>true</PublishAot>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,43 @@
// 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.Timers;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.VisualBasic;
namespace SamplePagesExtension;
public partial class SampleUpdatingItemsPage : ListPage
{
private readonly ListItem hourItem = new(new NoOpCommand());
private readonly ListItem minuteItem = new(new NoOpCommand());
private readonly ListItem secondItem = new(new NoOpCommand());
private static Timer timer;
public SampleUpdatingItemsPage()
{
Name = "Open";
Icon = new IconInfo("\uE72C");
}
public override IListItem[] GetItems()
{
if (timer == null)
{
timer = new Timer(500);
timer.Elapsed += (object source, ElapsedEventArgs e) =>
{
var current = DateAndTime.Now;
hourItem.Title = $"{current.Hour}";
minuteItem.Title = $"{current.Minute}";
secondItem.Title = $"{current.Second}";
};
timer.AutoReset = true; // Keep repeating
timer.Enabled = true;
}
return [hourItem, minuteItem, secondItem];
}
}

View File

@@ -0,0 +1,92 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
public partial class SamplesListPage : ListPage
{
private readonly IListItem[] _commands = [
// List pages
new ListItem(new SampleListPage())
{
Title = "List Page Sample Command",
Subtitle = "Display a list of items",
},
new ListItem(new SampleListPageWithDetails())
{
Title = "List Page With Details",
Subtitle = "A list of items, each with additional details to display",
},
new ListItem(new SampleUpdatingItemsPage())
{
Title = "List page with items that change",
Subtitle = "The items on the list update themselves in real time",
},
new ListItem(new SampleDynamicListPage())
{
Title = "Dynamic List Page Command",
Subtitle = "Changes the list of items in response to the typed query",
},
// Content pages
new ListItem(new SampleContentPage())
{
Title = "Sample content page",
Subtitle = "Display mixed forms, markdown, and other types of content",
},
new ListItem(new SampleTreeContentPage())
{
Title = "Sample nested content",
Subtitle = "Example of nesting a tree of content",
},
new ListItem(new SampleCommentsPage())
{
Title = "Sample of nested comments",
Subtitle = "Demo of using nested trees of content to create a comment thread-like experience",
Icon = new IconInfo("\uE90A"), // Comment
},
new ListItem(new SampleMarkdownPage())
{
Title = "Markdown Page Sample Command",
Subtitle = "Display a page of rendered markdown",
},
new ListItem(new SampleMarkdownManyBodies())
{
Title = "Markdown with multiple blocks",
Subtitle = "A page with multiple blocks of rendered markdown",
},
new ListItem(new SampleMarkdownDetails())
{
Title = "Markdown with details",
Subtitle = "A page with markdown and details",
},
// Settings helpers
new ListItem(new SampleSettingsPage())
{
Title = "Sample settings page",
Subtitle = "A demo of the settings helpers",
},
// Evil edge cases
// Anything weird that might break the palette - put that in here.
new ListItem(new EvilSamplesPage())
{
Title = "Evil samples",
Subtitle = "Samples designed to break the palette in many different evil ways",
}
];
public SamplesListPage()
{
Name = "Samples";
Icon = new IconInfo("\ue946"); // Info
}
public override IListItem[] GetItems() => _commands;
}

View File

@@ -0,0 +1,18 @@
// 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.Diagnostics;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
public partial class SelfImmolateCommand : InvokableCommand
{
public override ICommandResult Invoke()
{
Process.GetCurrentProcess().Kill();
return CommandResult.KeepOpen();
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="SamplePagesExtension.app"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>