diff --git a/New_Extensibility_Model/Samples/FeatureGallery/.vsextension/string-resources.json b/New_Extensibility_Model/Samples/FeatureGallery/.vsextension/string-resources.json new file mode 100644 index 00000000..00d62091 --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/.vsextension/string-resources.json @@ -0,0 +1,3 @@ +{ + "FeatureGallery.MainToolWindowCommand.DisplayName": "VisualStudio.Extensibility Feature Gallery" +} \ No newline at end of file diff --git a/New_Extensibility_Model/Samples/FeatureGallery/DocumentEditing/DocumentEditingTest.cs b/New_Extensibility_Model/Samples/FeatureGallery/DocumentEditing/DocumentEditingTest.cs new file mode 100644 index 00000000..3defa3cc --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/DocumentEditing/DocumentEditingTest.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery; + +using System; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility; +using System.IO; +using Microsoft.VisualStudio.RpcContracts.Documents; +using Microsoft.VisualStudio.Extensibility.Shell; + +[DataContract] +internal class DocumentEditingTest : TestData +{ + public DocumentEditingTest(VisualStudioExtensibility extensibility) + : base(extensibility) + { + } + + [DataMember] + public override string ButtonText => "Edit a document"; + + [DataMember] + public override string Description => "This command opens a new file and writes a random GUID in it. A prompt will ask to close the file."; + + protected override async Task RunAsync(IClientContext clientContext, CancellationToken cancellationToken) + { + var filePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".md"); + File.Create(filePath).Close(); + bool keepFile = false; + try + { + var textDocumentSnapshot = await this.Extensibility.Documents().OpenTextDocumentAsync(new(filePath), cancellationToken); + + await this.Extensibility.Editor().EditAsync( + batch => textDocumentSnapshot.AsEditable(batch).Insert(0, Guid.NewGuid().ToString()), + cancellationToken); + + if (!await this.Extensibility.Shell().ShowPromptAsync("Press OK to close and delete the file.", PromptOptions.OKCancel, cancellationToken)) + { + keepFile = true; + } + } + finally + { + if (!keepFile) + { + await this.Extensibility.Documents().CloseDocumentAsync(new(filePath), SaveDocumentOption.NoSave, cancellationToken); + File.Delete(filePath); + } + } + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/EditorMarginTest.cs b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/EditorMarginTest.cs new file mode 100644 index 00000000..ead55298 --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/EditorMarginTest.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery; + +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.Editor; +using Microsoft.VisualStudio.Extensibility.Shell; +using Microsoft.VisualStudio.RpcContracts.Documents; + +[DataContract] +internal class EditorMarginTest : TestData +{ + public EditorMarginTest(VisualStudioExtensibility extensibility) + : base(extensibility) + { + } + + [DataMember] + public override string ButtonText => "Editor margin"; + + [DataMember] + public override string Description => "This command opens a text document with a custom editor margin counting the words in the document. A prompt will ask to close the file."; + + protected override async Task RunAsync(IClientContext clientContext, CancellationToken cancellationToken) + { + var filePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".txt"); + bool keepFile = false; + + using var file = new StreamWriter(File.Create(filePath)); + try + { + await file.WriteAsync(""" + using System; + + public class Class1 + { + public Class1() + { + } + } + """); + file.Close(); + + var textDocumentSnapshot = await this.Extensibility.Documents().OpenTextDocumentAsync(new(filePath), cancellationToken); + + if (!await this.Extensibility.Shell().ShowPromptAsync("Press OK to close and delete the file.", PromptOptions.OKCancel, cancellationToken)) + { + keepFile = true; + } + } + finally + { + if (!keepFile) + { + await this.Extensibility.Documents().CloseDocumentAsync(new(filePath), SaveDocumentOption.NoSave, cancellationToken); + File.Delete(filePath); + } + } + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountControl.cs b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountControl.cs new file mode 100644 index 00000000..458505c5 --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountControl.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery.EditorMargin; + +using Microsoft.VisualStudio.Extensibility.UI; + +/// +/// A sample remote user control to use as the margin content. +/// +internal class WordCountControl : RemoteUserControl +{ + /// + /// Initializes a new instance of the class. + /// + /// + /// Data context of the remote control which can be referenced from xaml through data binding. + /// + public WordCountControl(object? dataContext) + : base(dataContext) + { + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountControl.xaml b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountControl.xaml new file mode 100644 index 00000000..41c16aa2 --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountControl.xaml @@ -0,0 +1,10 @@ + + + + Words: + + + + \ No newline at end of file diff --git a/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountData.cs b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountData.cs new file mode 100644 index 00000000..6a2c8eff --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountData.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery.EditorMargin; + +using System.Runtime.Serialization; +using Microsoft.VisualStudio.Extensibility.UI; + +[DataContract] +public class WordCountData : NotifyPropertyChangedObject +{ + private int wordCount; + + [DataMember] + public int WordCount + { + get => this.wordCount; + set => this.SetProperty(ref this.wordCount, value); + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountMarginProvider.cs b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountMarginProvider.cs new file mode 100644 index 00000000..8c42c4d0 --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/EditorMargin/WordCountMarginProvider.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery.EditorMargin; + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.Editor; +using Microsoft.VisualStudio.RpcContracts.RemoteUI; + +/// +/// A sample text view margin provider, which adds a margin to the Visual Studio editor status bar, to the left +/// of the built-in line number margin, indicating number of words in the current text document. +/// +[VisualStudioContribution] +internal class WordCountMarginProvider : ExtensionPart, ITextViewMarginProvider, ITextViewOpenClosedListener, ITextViewChangedListener +{ + private readonly Dictionary dataModels = new(); + + /// + /// Configures this extension part to be applied to any text view. + /// + public TextViewExtensionConfiguration TextViewExtensionConfiguration => new() + { + AppliesTo = new[] + { + DocumentFilter.FromDocumentType(DocumentType.KnownValues.Text), + }, + }; + + /// + /// Configures the margin to be placed to the left of built-in Visual Studio line number margin. + /// + public TextViewMarginProviderConfiguration TextViewMarginProviderConfiguration => + new(marginContainer: ContainerMarginPlacement.KnownValues.BottomRightCorner) + { + Before = new[] { MarginPlacement.KnownValues.RowMargin }, + }; + + /// + /// Creates a remotable visual element representing the content of the margin. + /// + public Task CreateVisualElementAsync(ITextViewSnapshot textView, CancellationToken cancellationToken) + { + var dataModel = new WordCountData(); + dataModel.WordCount = CountWords(textView.Document); + this.dataModels[textView.Uri] = dataModel; + return Task.FromResult(new WordCountControl(dataModel)); + } + + /// + public Task TextViewChangedAsync(TextViewChangedArgs args, CancellationToken cancellationToken) + { + this.dataModels[args.AfterTextView.Uri].WordCount = CountWords(args.AfterTextView.Document); + return Task.CompletedTask; + } + + /// + public Task TextViewClosedAsync(ITextViewSnapshot textView, CancellationToken cancellationToken) + { + this.dataModels.Remove(textView.Uri); + return Task.CompletedTask; + } + + /// + public Task TextViewOpenedAsync(ITextViewSnapshot textView, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + private static int CountWords(ITextDocumentSnapshot documentSnapshot) + { + int wordCount = 0; + for (int i = 1; i < documentSnapshot.Length; i++) + { + if (char.IsWhiteSpace(documentSnapshot[i - 1]) && char.IsLetterOrDigit(documentSnapshot[i])) + { + wordCount++; + } + } + + return wordCount; + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/FeatureGallery.csproj b/New_Extensibility_Model/Samples/FeatureGallery/FeatureGallery.csproj new file mode 100644 index 00000000..81c76fb9 --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/FeatureGallery.csproj @@ -0,0 +1,32 @@ + + + net8.0-windows8.0 + enable + 11 + en-US + $(NoWarn);CS1591;CA1812;CA1303;SA1600 + + + https://pkgs.dev.azure.com/azure-public/vside/_packaging/msft_consumption/nuget/v3/index.json;$(RestoreAdditionalProjectSources) + + + + + + + + + + + + + + MSBuild:Compile + + + + MSBuild:Compile + + + + diff --git a/New_Extensibility_Model/Samples/FeatureGallery/FeatureGalleryExtension.cs b/New_Extensibility_Model/Samples/FeatureGallery/FeatureGalleryExtension.cs new file mode 100644 index 00000000..9dac559e --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/FeatureGalleryExtension.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery; + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.Extensibility; + +/// +/// Extension entry point for the ToolWindowSample. +/// +[VisualStudioContribution] +public class FeatureGalleryExtension : Extension +{ + /// + public override ExtensionConfiguration ExtensionConfiguration => new() + { + Metadata = new( + id: "FeatureGalleryExtension.f83f7a5e-61aa-4bb6-8f25-1cd2764e0123", + version: this.ExtensionAssemblyVersion, + publisherName: "Microsoft", + displayName: "VisualStudio.Extensibility Feature Gallery", + description: "An extension demonstrating multiple Visual Studio extension points."), + }; + + /// + protected override void InitializeServices(IServiceCollection serviceCollection) + { + base.InitializeServices(serviceCollection); + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindow.cs b/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindow.cs new file mode 100644 index 00000000..cc780395 --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindow.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery; + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Documents; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.ToolWindows; +using Microsoft.VisualStudio.RpcContracts.RemoteUI; + +/// +/// A sample tool window. +/// +[VisualStudioContribution] +public class MainToolWindow : ToolWindow +{ + private readonly IReadOnlyList tests; + + /// + /// Initializes a new instance of the class. + /// + public MainToolWindow() + { + this.Title = "VisualStudio.Extensibility Feature Gallery"; + this.tests = new TestData[] + { + new DocumentEditingTest(this.Extensibility), + new ModalDialogTest(this.Extensibility), + new EditorMarginTest(this.Extensibility), + }; + } + + /// + public override ToolWindowConfiguration ToolWindowConfiguration => new() + { + Placement = ToolWindowPlacement.Floating, + AllowAutoCreation = true, + }; + + /// + public override Task GetContentAsync(CancellationToken cancellationToken) + { + return Task.FromResult(new MainToolWindowControl(this.tests)); + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowCommand.cs b/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowCommand.cs new file mode 100644 index 00000000..36a9592b --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowCommand.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery; + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility; +using Microsoft.VisualStudio.Extensibility.Commands; + +/// +/// A sample command for showing a tool window. +/// +[VisualStudioContribution] +public class MainToolWindowCommand : Command +{ + /// + /// Initializes a new instance of the class. + /// + public MainToolWindowCommand() + { + } + + /// + public override CommandConfiguration CommandConfiguration => new("%FeatureGallery.MainToolWindowCommand.DisplayName%") + { + Placements = new[] { CommandPlacement.KnownPlacements.ExtensionsMenu }, + Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText), + }; + + /// + public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) + { + await this.Extensibility.Shell().ShowToolWindowAsync(activate: true, cancellationToken); + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowControl.cs b/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowControl.cs new file mode 100644 index 00000000..02dfa84f --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowControl.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace FeatureGallery; + +using System.Threading; +using Microsoft.VisualStudio.Extensibility.UI; + +/// +/// A sample remote user control to use as tool window UI content. +/// +internal class MainToolWindowControl : RemoteUserControl +{ + /// + /// Initializes a new instance of the class. + /// + /// + /// Data context of the remote control which can be referenced from xaml through data binding. + /// + public MainToolWindowControl(object? dataContext) + : base(dataContext) + { + } +} diff --git a/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowControl.xaml b/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowControl.xaml new file mode 100644 index 00000000..b2ad9e18 --- /dev/null +++ b/New_Extensibility_Model/Samples/FeatureGallery/MainToolWindowControl.xaml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + +