├── BrightXaml.ExtensibilityTests ├── Resources │ ├── SingleLine01_Good.xml │ ├── SingleLine02_Good.xml │ ├── SingleLine03_Good.xml │ ├── SingleLine04_Good.xml │ ├── MultipleLine01_Bad.xml │ ├── SingleLine01_Bad.xml │ ├── MultipleLine03_Bad.xml │ ├── SingleLine02_Bad.xml │ ├── SingleLine03_Bad.xml │ ├── SingleLine04_Bad.xml │ ├── MultipleLine01_Good.xml │ ├── MultipleLine03_Good.xml │ ├── MultipleLine02_Bad.xml │ ├── SingleLineComment01_Bad.xml │ ├── SingleLineComment01_Good.xml │ ├── SingleLineComment02_Bad.xml │ ├── SingleLineComment02_Good.xml │ ├── MultipleLine02_Good.xml │ ├── SingleLine05_Good.xml │ ├── SingleLine05_Bad.xml │ ├── MultipleLine04_Bad.xml │ ├── MultipleLine04_Good.xml │ ├── MultipleLine05_Bad.xml │ ├── MultipleLine05_Good.xml │ ├── MultipleLine08_Bad.xml │ ├── MultipleLine07_Bad.xml │ ├── SplitTagsPerLine02_Bad.xml │ ├── SplitTagsPerLine01_Bad.xml │ ├── SplitTagsPerLine02_Good.xml │ ├── MultipleLine06_Bad.xml │ ├── MultipleLine07_Good.xml │ ├── MultipleLine08_Good.xml │ ├── SplitTagsPerLine01_Good.xml │ ├── MultipleLine06_Good.xml │ ├── RemoveEmpty_MultipleLine01_Good.xml │ ├── RemoveEmpty_MultipleLine01_Bad.xml │ ├── RemoveEmpty_MultipleLine02_Good.xml │ ├── RemoveEmpty_MultipleLine02_Bad.xml │ ├── FullDocument01_Bad.xml │ ├── FullDocument01_Good.xml │ ├── FullDocument02_Bad.xml │ └── FullDocument02_Good.xml ├── MockEntrypoint.cs ├── Utilities │ ├── ShowDefinitionHelperTests.cs │ └── ViewModelHelperTests.cs └── TestHelper.cs ├── .editorconfig ├── BrightGit.Extensibility ├── .vsextension │ └── string-resources.json ├── Services │ ├── EFCoreManagerService.cs │ ├── SettingsEFCoreData.cs │ ├── IDialogService.cs │ ├── TabsStorageData.cs │ ├── SettingsData.cs │ ├── SettingsTabsData.cs │ ├── DialogService.cs │ ├── SettingsService.cs │ └── TabsStorageService.cs ├── Meta.cs ├── Models │ ├── TabDocumentInfo.cs │ └── TabsInfo.cs ├── Listeners │ ├── SolutionSubscriptionObserver.cs │ ├── SolutionTrackerObserver.cs │ └── GitSharpHookListener.cs ├── Windows │ ├── TabsWindowContent.cs │ ├── SettingsWindowContent.cs │ ├── SettingsWindowCommand.cs │ ├── TabsWindowCommand.cs │ ├── TabsWindow.cs │ ├── SettingsWindowViewModel.cs │ ├── TabsWindowViewModel.cs │ ├── SettingsWindow.cs │ └── SettingsWindowContent.xaml ├── Helpers │ ├── LibGit2SharpHelper.cs │ └── VSHelper.cs ├── BrightGit.Extensibility.csproj ├── Commands │ ├── EFGitTest.cs │ ├── EFGitMigrationHookAddCommand.cs │ ├── EFGitMigrationHookRemoveCommand.cs │ ├── EFGitMigrationHookCheckCommand.cs │ ├── TabsSortCommand.cs │ ├── TabsRestoreCommand.cs │ └── TabsSaveCommand.cs └── ExtensionEntrypoint.cs ├── BrightXaml.Extensibility ├── .vsextension │ └── string-resources.json ├── Models │ ├── CommandInfo.cs │ ├── ComboIntData.cs │ └── BindingDefinitionOffsets.cs ├── Meta.cs ├── Properties │ └── launchSettings.json ├── Services │ ├── SettingsGoToBindingData.cs │ ├── SettingsFormatXamlData.cs │ ├── SettingsData.cs │ ├── IDialogService.cs │ ├── SettingsPropInpcData.cs │ ├── SettingsService.cs │ └── DialogService.cs ├── Utilities │ ├── PropertyLineData.cs │ ├── ExportFilesHelper.cs │ └── ViewModelHelper.cs ├── Windows │ ├── HelpWindowContent.cs │ ├── ProgressWindowContent.cs │ ├── ChooseItemWindowContent.cs │ ├── ProgressWindowViewModel.cs │ ├── SettingsWindowContent.cs │ ├── HelpWindowCommand.cs │ ├── ChooseItemWindowViewModel.cs │ ├── SettingsWindowCommand.cs │ ├── ChooseItemWindowCommand.cs │ ├── ProgressWindowCommand.cs │ ├── ProgressWindowContent.xaml │ ├── HelpWindow.cs │ ├── ChooseItemWindowContent.xaml │ ├── ProgressWindow.cs │ ├── ChooseItemWindow.cs │ ├── SettingsWindow.cs │ ├── HelpWindowViewModel.cs │ └── HelpWindowContent.xaml ├── BrightXaml.Extensibility.csproj ├── Commands │ ├── ExtractViewCommand.cs │ ├── ShowViewCommand.cs │ ├── DevOpenSolutionCommand.cs │ ├── ShowCodeBehindCommand.cs │ ├── KillXamlDesignerCommand.cs │ ├── ExtractClassesInUseCommand.cs │ ├── HelloWorldCommand.cs │ ├── CleanBinAndObjCommand.cs │ ├── FormatXamlCommand.cs │ └── ExtractFolderCommand.cs ├── Helpers │ ├── VSHelper.cs │ └── ClipboardHelper.cs └── ExtensionEntrypoint.cs ├── BrightGit.SharpHook ├── Properties │ ├── launchSettings.json │ └── PublishProfiles │ │ └── FolderProfile.pubxml ├── BrightGit.SharpHook.csproj └── Program.cs ├── BrightGit.SharpAutoMigrator ├── Readme.txt ├── Resources │ └── post-checkout ├── BrightGit.SharpAutoMigrator.csproj ├── Properties │ └── PublishProfiles │ │ └── FolderProfile.pubxml └── DotnetHelper.cs ├── BrightGit.SharpCommon ├── Models │ ├── RunData.cs │ ├── RunType.cs │ └── GitHookType.cs ├── BrightGit.SharpCommon.csproj ├── SharpRunHelper.cs ├── Helpers │ └── MigratorHelper.cs ├── DotnetHelper.cs └── SharpHookHelper.cs ├── BrightGit.SharpRun └── BrightGit.SharpRun.csproj ├── .github └── workflows │ └── dotnet.yml ├── LICENSE └── .gitattributes /BrightXaml.ExtensibilityTests/Resources/SingleLine01_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine02_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine03_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine04_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # CEE0027: String not localized 4 | dotnet_diagnostic.CEE0027.severity = silent 5 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine01_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine01_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine03_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine02_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine03_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine04_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine01_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine03_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/.vsextension/string-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "BrightGit.Extensibility.Command1.DisplayName": "Sample Remote Command" 3 | } 4 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine02_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLineComment01_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLineComment01_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLineComment02_Bad.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Services/EFCoreManagerService.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Services; 2 | public class EFCoreManagerService 3 | { 4 | } 5 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/.vsextension/string-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "BrightXaml.Extensibility.HelloWorldCommand.DisplayName": "Hello World Command" 3 | } 4 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLineComment02_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine02_Good.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine05_Good.xml: -------------------------------------------------------------------------------- 1 | x:Class="ChatGPT.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" -------------------------------------------------------------------------------- /BrightGit.SharpHook/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "BrightGit.ConsoleHooks": { 4 | "commandName": "Project", 5 | "commandLineArgs": "arg1\r\narg2\r\narg3" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SingleLine05_Bad.xml: -------------------------------------------------------------------------------- 1 | x:Class="ChatGPT.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" -------------------------------------------------------------------------------- /BrightGit.SharpAutoMigrator/Readme.txt: -------------------------------------------------------------------------------- 1 | - Publish Options - Console 2 | Self-Contained 3 | 35MB 4 | 5 | Self Contained and EnableCompressionInSingleFile and PublishTrimmed 6 | 11.5MB 7 | 8 | Not self contained (requires .NET) 9 | 2.3MB -------------------------------------------------------------------------------- /BrightGit.SharpCommon/Models/RunData.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.SharpCommon.Models; 2 | public class RunData 3 | { 4 | public RunType RunType { get; set; } 5 | public string RepoDir { get; set; } 6 | public string[] Parameters { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /BrightGit.SharpCommon/Models/RunType.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.SharpCommon.Models; 2 | public enum RunType 3 | { 4 | EFMigrationDown, 5 | EFMigrationUp, 6 | GitUndoChanges, 7 | GitStashChanges, 8 | GitStashPop, 9 | GitStashApply, 10 | } 11 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/MockEntrypoint.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Extensibility; 2 | 3 | namespace BrightXaml.ExtensibilityTests; 4 | [VisualStudioContribution] 5 | internal class MockEntrypoint : Extension 6 | { 7 | public override ExtensionConfiguration ExtensionConfiguration => null; 8 | } 9 | -------------------------------------------------------------------------------- /BrightGit.SharpAutoMigrator/Resources/post-checkout: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #dotnet-script '.git\hooks\post-checkout.csx' -- $1 $2 $3 3 | #exec .\.git\hooks\EFCoreGitHelper.exe "$1" "$2" "$3" 4 | exec "D:\Projects Visual Studio\Bright Soft Projects\BrightExtensions\EFCoreGitHelper\bin\Debug\EFCoreGitHelper.exe" "$1" "$2" "$3" -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Models/CommandInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace BrightXaml.Extensibility.Models; 4 | [DataContract] 5 | internal class CommandInfo 6 | { 7 | [DataMember] 8 | public string Name { get; set; } 9 | 10 | [DataMember] 11 | public string Description { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Meta.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace BrightGit.Extensibility; 4 | internal static class Meta 5 | { 6 | public static Version Version { get; } = Assembly.GetExecutingAssembly().GetName().Version; 7 | 8 | public static bool IsDebug { get; } = 9 | #if DEBUG 10 | true; 11 | #else 12 | false; 13 | #endif 14 | } 15 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Meta.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace BrightXaml.Extensibility; 4 | internal static class Meta 5 | { 6 | public static Version Version { get; } = Assembly.GetExecutingAssembly().GetName().Version; 7 | 8 | public static bool IsDebug { get; } = 9 | #if DEBUG 10 | true; 11 | #else 12 | false; 13 | #endif 14 | } 15 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "BrightXaml.Extensibility": { 4 | "commandName": "Project" 5 | }, 6 | "BrightXaml.Extensibility Debug": { 7 | "commandName": "Project", 8 | "commandLineArgs": "\"D:\\Projects Visual Studio\\Test Projects\\TestWPFNETCore\\TestWPFNETCore.sln\"" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine04_Bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0-windows 4 | enable 5 | disable 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Models/ComboIntData.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Runtime.Serialization; 3 | 4 | namespace BrightXaml.Extensibility.Models; 5 | [DataContract] 6 | public class ComboIntData : ObservableObject 7 | { 8 | [DataMember] 9 | public int Id { get; set; } 10 | 11 | [DataMember] 12 | public string Text { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine04_Good.xml: -------------------------------------------------------------------------------- 1 | isEnabled; set => SetProperty(ref isEnabled, value); } 10 | private bool isEnabled; 11 | } 12 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Services/SettingsGoToBindingData.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Runtime.Serialization; 3 | 4 | namespace BrightXaml.Extensibility.Services; 5 | [DataContract] 6 | public class SettingsGoToBindingData : ObservableObject 7 | { 8 | [DataMember] 9 | public bool IsEnabled { get => isEnabled; set => SetProperty(ref isEnabled, value); } 10 | private bool isEnabled = true; 11 | } 12 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Models/BindingDefinitionOffsets.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Models; 2 | public class BindingDefinitionOffsets 3 | { 4 | public string BindingWord { get; set; } 5 | 6 | public int Line { get; set; } 7 | public int OffsetFromFile { get; set; } 8 | public int OffsetFromLine { get; set; } 9 | 10 | //public int AttributeLine { get; set; } 11 | //public int TargetLine { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Utilities/PropertyLineData.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Utilities; 2 | public class PropertyLineData 3 | { 4 | public string Indentation { get; set; } 5 | public string Access { get; set; } 6 | public string Type { get; set; } 7 | public string Name { get; set; } 8 | public string GetAccess { get; set; } 9 | public string SetAccess { get; set; } 10 | public string DefaultValue { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Services/IDialogService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Extensibility.Shell; 2 | 3 | namespace BrightGit.Extensibility.Services; 4 | public interface IDialogService 5 | { 6 | ShellExtensibility Shell { get; set; } 7 | 8 | /// 9 | /// Only use this for a maximum of 5 items... It displays horizontally only. 10 | /// 11 | Task ShowPromptOptionsAsync(string title, List items, CancellationToken cancellationToken); 12 | } -------------------------------------------------------------------------------- /BrightGit.Extensibility/Models/TabDocumentInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace BrightGit.Extensibility.Models; 4 | [DataContract] 5 | public class TabDocumentInfo 6 | { 7 | [DataMember] 8 | public string FilePath { get; set; } 9 | 10 | [DataMember] 11 | public int Index { get; set; } 12 | 13 | [DataMember] 14 | public bool IsPinned { get; set; } 15 | 16 | [DataMember] 17 | public string FileName => (!string.IsNullOrWhiteSpace(FilePath)) ? Path.GetFileName(FilePath) : string.Empty; 18 | } 19 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/HelpWindowContent.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility.UI; 4 | 5 | /// 6 | /// A remote user control to use as tool window UI content. 7 | /// 8 | internal class HelpWindowContent : RemoteUserControl 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | public HelpWindowContent() 14 | : base(dataContext: new HelpWindowViewModel()) 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine05_Bad.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine05_Good.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine08_Bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine07_Bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SplitTagsPerLine02_Bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SplitTagsPerLine01_Bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SplitTagsPerLine02_Good.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Listeners/SolutionSubscriptionObserver.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.ProjectSystem.Query; 2 | using System.Diagnostics; 3 | 4 | namespace BrightGit.Extensibility.Listeners; 5 | public class SolutionSubscriptionObserver : IObserver> 6 | { 7 | public void OnCompleted() 8 | { 9 | Debug.WriteLine("SolutionSubscriptionObserver.OnCompleted"); 10 | } 11 | 12 | public void OnError(Exception error) 13 | { } 14 | 15 | public void OnNext(IQueryResults value) 16 | { 17 | Debug.WriteLine("SolutionSubscriptionObserver.OnNext"); 18 | } 19 | } -------------------------------------------------------------------------------- /BrightGit.SharpHook/BrightGit.SharpHook.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net8.0-windows 5 | enable 6 | disable 7 | 1.0.0 8 | 9 | false 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /BrightGit.SharpRun/BrightGit.SharpRun.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net8.0-windows 5 | enable 6 | disable 7 | 1.0.0 8 | 9 | false 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine06_Bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine07_Good.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine08_Good.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/SplitTagsPerLine01_Good.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/MultipleLine06_Good.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/RemoveEmpty_MultipleLine01_Good.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Services/TabsStorageData.cs: -------------------------------------------------------------------------------- 1 | using BrightGit.Extensibility.Models; 2 | using Microsoft.VisualStudio.PlatformUI; 3 | using System.Runtime.Serialization; 4 | 5 | namespace BrightGit.Extensibility.Services; 6 | [DataContract] 7 | public class TabsStorageData : ObservableObject 8 | { 9 | [DataMember] 10 | public List TabsBranch { get => tabsBranch; set => SetProperty(ref tabsBranch, value); } 11 | private List tabsBranch = new(); 12 | 13 | [DataMember] 14 | public List TabsCustom { get => tabsCustom; set => SetProperty(ref tabsCustom, value); } 15 | private List tabsCustom = new(); 16 | } 17 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ProgressWindowContent.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility.UI; 4 | 5 | /// 6 | /// A remote user control to use as tool window UI content. 7 | /// 8 | internal class ProgressWindowContent : RemoteUserControl 9 | { 10 | public ProgressWindowViewModel ViewModel => base.DataContext as ProgressWindowViewModel; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public ProgressWindowContent() 16 | : base(dataContext: new ProgressWindowViewModel()) 17 | { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Utilities/ShowDefinitionHelperTests.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Utilities.Tests; 2 | 3 | [TestClass()] 4 | public class ShowDefinitionHelperTests 5 | { 6 | [TestMethod()] 7 | [DataRow(" 6 | /// A remote user control to use as tool window UI content. 7 | /// 8 | internal class ChooseItemWindowContent : RemoteUserControl 9 | { 10 | public ChooseItemWindowViewModel ViewModel => base.DataContext as ChooseItemWindowViewModel; 11 | 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public ChooseItemWindowContent() 16 | : base(dataContext: new ChooseItemWindowViewModel()) 17 | { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/RemoveEmpty_MultipleLine01_Bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Services/SettingsData.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Runtime.Serialization; 3 | 4 | namespace BrightGit.Extensibility.Services; 5 | [DataContract] 6 | public class SettingsData : ObservableObject 7 | { 8 | [DataMember] 9 | public SettingsEFCoreData EFCore { get => efcore; set => SetProperty(ref efcore, value); } 10 | private SettingsEFCoreData efcore; 11 | 12 | [DataMember] 13 | public SettingsTabsData Tabs { get => tabs; set => SetProperty(ref tabs, value); } 14 | private SettingsTabsData tabs; 15 | 16 | public SettingsData() 17 | { 18 | Tabs = new SettingsTabsData(); 19 | EFCore = new SettingsEFCoreData(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/RemoveEmpty_MultipleLine02_Good.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Windows/TabsWindowContent.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Windows; 2 | 3 | using BrightGit.Extensibility.Services; 4 | using Microsoft.VisualStudio.Extensibility.UI; 5 | 6 | /// 7 | /// A remote user control to use as tool window UI content. 8 | /// 9 | internal class TabsWindowContent : RemoteUserControl 10 | { 11 | public TabsWindowViewModel ViewModel => base.DataContext as TabsWindowViewModel; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public TabsWindowContent(TabsStorageService tabsStorageService) 17 | : base(dataContext: new TabsWindowViewModel(tabsStorageService)) 18 | { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Windows/SettingsWindowContent.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Windows; 2 | 3 | using BrightGit.Extensibility.Services; 4 | using Microsoft.VisualStudio.Extensibility.UI; 5 | 6 | /// 7 | /// A remote user control to use as tool window UI content. 8 | /// 9 | internal class SettingsWindowContent : RemoteUserControl 10 | { 11 | public SettingsWindowViewModel ViewModel => base.DataContext as SettingsWindowViewModel; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public SettingsWindowContent(SettingsService settingsService) 17 | : base(dataContext: new SettingsWindowViewModel(settingsService)) 18 | { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ProgressWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility.UI; 4 | using System.Runtime.Serialization; 5 | 6 | [DataContract] 7 | internal class ProgressWindowViewModel : NotifyPropertyChangedObject 8 | { 9 | [DataMember] 10 | public int ProgressValue { get => _progressValue; set => SetProperty(ref _progressValue, value); } 11 | private int _progressValue; 12 | 13 | [DataMember] 14 | public string ProgressText { get => _progressText; set => SetProperty(ref _progressText, value); } 15 | private string _progressText; 16 | 17 | public ProgressWindowViewModel() 18 | { 19 | ProgressValue = 0; 20 | ProgressText = "Starting..."; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/SettingsWindowContent.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using BrightXaml.Extensibility.Services; 4 | using Microsoft.VisualStudio.Extensibility.UI; 5 | 6 | /// 7 | /// A remote user control to use as tool window UI content. 8 | /// 9 | internal class SettingsWindowContent : RemoteUserControl 10 | { 11 | public SettingsWindowViewModel ViewModel => base.DataContext as SettingsWindowViewModel; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public SettingsWindowContent(SettingsService settingsService) 17 | : base(dataContext: new SettingsWindowViewModel(settingsService)) 18 | { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Resources/RemoveEmpty_MultipleLine02_Bad.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Services/SettingsTabsData.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Runtime.Serialization; 3 | 4 | namespace BrightGit.Extensibility.Services; 5 | [DataContract] 6 | public class SettingsTabsData : ObservableObject 7 | { 8 | [DataMember] 9 | public bool IsEnabled { get => isEnabled; set => SetProperty(ref isEnabled, value); } 10 | private bool isEnabled; 11 | 12 | [DataMember] 13 | public bool CloseTabsOnSave { get => closeTabsOnSave; set => SetProperty(ref closeTabsOnSave, value); } 14 | private bool closeTabsOnSave; 15 | 16 | [DataMember] 17 | public bool CloseTabsOnBranchChange { get => closeTabsOnBranchChange; set => SetProperty(ref closeTabsOnBranchChange, value); } 18 | private bool closeTabsOnBranchChange = true; 19 | } 20 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Helpers/LibGit2SharpHelper.cs: -------------------------------------------------------------------------------- 1 | using LibGit2Sharp; 2 | using System.Reflection; 3 | 4 | namespace BrightGit.Extensibility.Helpers; 5 | internal static class LibGit2SharpHelper 6 | { 7 | public static void RegisterNativePath(string path) 8 | { 9 | // We check first because if we overwrite after in use, it will throw an exception. 10 | if (GlobalSettings.NativeLibraryPath == null) 11 | { 12 | // Set the native library path for LibGit2Sharp when inside VS extension (VSIX). 13 | string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 14 | assemblyFolder = assemblyFolder[..^2]; 15 | GlobalSettings.NativeLibraryPath = Path.Combine(assemblyFolder, "runtimes", "win-x64", "native"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /BrightGit.SharpAutoMigrator/BrightGit.SharpAutoMigrator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net8.0-windows 5 | enable 6 | disable 7 | 1.0.0 8 | 9 | false 10 | false 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Models/TabsInfo.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Runtime.Serialization; 3 | 4 | namespace BrightGit.Extensibility.Models; 5 | [DataContract] 6 | public class TabsInfo : ObservableObject 7 | { 8 | [DataMember] 9 | public string Id { get; set; } 10 | 11 | [DataMember] 12 | public string SolutionName { get; set; } 13 | 14 | [DataMember] 15 | public string BranchName { get; set; } 16 | 17 | [DataMember] 18 | public string Name { get => name; set => SetProperty(ref name, value); } 19 | private string name; 20 | 21 | [DataMember] 22 | public DateTime DateSaved { get => dateSaved; set => SetProperty(ref dateSaved, value); } 23 | private DateTime dateSaved; 24 | 25 | [DataMember] 26 | public List Tabs { get; set; } = new(); 27 | } 28 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Listeners/SolutionTrackerObserver.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.ProjectSystem.Query; 2 | 3 | namespace BrightGit.Extensibility.Listeners; 4 | 5 | // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. 6 | #pragma warning disable VSEXTPREVIEW_PROJECTQUERY_TRACKING 7 | 8 | public class SolutionTrackerObserver : IObserver> 9 | { 10 | public void OnCompleted() 11 | { } 12 | 13 | public void OnError(Exception error) 14 | { } 15 | 16 | public void OnNext(IQueryTrackUpdates value) 17 | { } 18 | } 19 | 20 | // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. 21 | #pragma warning restore VSEXTPREVIEW_PROJECTQUERY_TRACKING -------------------------------------------------------------------------------- /BrightGit.SharpHook/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\publish\ 10 | FileSystem 11 | <_TargetId>Folder 12 | net8.0-windows 13 | win-x64 14 | false 15 | true 16 | true 17 | true 18 | false 19 | 20 | -------------------------------------------------------------------------------- /BrightGit.SharpAutoMigrator/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | bin\Release\publish\ 10 | FileSystem 11 | <_TargetId>Folder 12 | net8.0-windows 13 | win-x64 14 | false 15 | true 16 | true 17 | true 18 | false 19 | 20 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/HelpWindowCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.Commands; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | [VisualStudioContribution] 9 | public class HelpWindowCommand : Command 10 | { 11 | /// 12 | public override CommandConfiguration CommandConfiguration => new(displayName: "Help") 13 | { 14 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 15 | Icon = new(ImageMoniker.KnownValues.QuestionMark, IconSettings.IconAndText), 16 | }; 17 | 18 | /// 19 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 20 | { 21 | await this.Extensibility.Shell().ShowToolWindowAsync(activate: true, cancellationToken); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ChooseItemWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility.UI; 4 | using System.Collections.ObjectModel; 5 | using System.Runtime.Serialization; 6 | 7 | [DataContract] 8 | internal class ChooseItemWindowViewModel : NotifyPropertyChangedObject 9 | { 10 | [DataMember] 11 | public ObservableCollection Items { get => _items; set => SetProperty(ref _items, value); } 12 | private ObservableCollection _items = new ObservableCollection(); 13 | 14 | [DataMember] 15 | public string SelectedItem { get => _selectedItem; set => SetProperty(ref _selectedItem, value); } 16 | private string _selectedItem; 17 | 18 | [DataMember] 19 | public string LabelText { get => _labelText; set => SetProperty(ref _labelText, value); } 20 | private string _labelText; 21 | 22 | public ChooseItemWindowViewModel() 23 | { } 24 | } -------------------------------------------------------------------------------- /BrightGit.Extensibility/Windows/SettingsWindowCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.Commands; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | [VisualStudioContribution] 9 | public class SettingsWindowCommand : Command 10 | { 11 | /// 12 | public override CommandConfiguration CommandConfiguration => new(displayName: "Settings") 13 | { 14 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 15 | Icon = new(ImageMoniker.KnownValues.Settings, IconSettings.IconAndText), 16 | }; 17 | 18 | /// 19 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 20 | { 21 | await this.Extensibility.Shell().ShowToolWindowAsync(activate: true, cancellationToken); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/SettingsWindowCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.Commands; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | [VisualStudioContribution] 9 | public class SettingsWindowCommand : Command 10 | { 11 | /// 12 | public override CommandConfiguration CommandConfiguration => new(displayName: "Settings") 13 | { 14 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 15 | Icon = new(ImageMoniker.KnownValues.Settings, IconSettings.IconAndText), 16 | }; 17 | 18 | /// 19 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 20 | { 21 | await this.Extensibility.Shell().ShowToolWindowAsync(activate: true, cancellationToken); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Windows/TabsWindowCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.Commands; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | [VisualStudioContribution] 9 | public class TabsWindowCommand : Command 10 | { 11 | /// 12 | public override CommandConfiguration CommandConfiguration => new(displayName: "View Saved Tabs") 13 | { 14 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 15 | Icon = new(ImageMoniker.KnownValues.ProcedureSettings, IconSettings.IconAndText), 16 | }; 17 | 18 | /// 19 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 20 | { 21 | await this.Extensibility.Shell().ShowToolWindowAsync(activate: true, cancellationToken); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Services/SettingsFormatXamlData.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Runtime.Serialization; 3 | 4 | namespace BrightXaml.Extensibility.Services; 5 | [DataContract] 6 | public class SettingsFormatXamlData : ObservableObject 7 | { 8 | [DataMember] 9 | public bool RemoveEmptyLines { get => removeEmptyLines; set => SetProperty(ref removeEmptyLines, value); } 10 | private bool removeEmptyLines = true; 11 | 12 | [DataMember] 13 | public int ClosingTagSpaces { get => closingTagSpaces; set => SetProperty(ref closingTagSpaces, value); } 14 | private int closingTagSpaces = -1; 15 | 16 | [DataMember] 17 | public int EndingTagSpaces { get => endingTagSpaces; set => SetProperty(ref endingTagSpaces, value); } 18 | private int endingTagSpaces = -1; 19 | 20 | [DataMember] 21 | public bool? IndentWithHeader { get => indentWithHeader; set => SetProperty(ref indentWithHeader, value); } 22 | private bool? indentWithHeader = null; 23 | } 24 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Services/SettingsData.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Runtime.Serialization; 3 | 4 | namespace BrightXaml.Extensibility.Services; 5 | [DataContract] 6 | public class SettingsData : ObservableObject 7 | { 8 | [DataMember] 9 | public SettingsPropInpcData PropInpc { get => propInpc; set => SetProperty(ref propInpc, value); } 10 | private SettingsPropInpcData propInpc; 11 | 12 | [DataMember] 13 | public SettingsFormatXamlData FormatXaml { get => formatXaml; set => SetProperty(ref formatXaml, value); } 14 | private SettingsFormatXamlData formatXaml; 15 | 16 | [DataMember] 17 | public SettingsGoToBindingData GoToBinding { get => goToBinding; set => SetProperty(ref goToBinding, value); } 18 | private SettingsGoToBindingData goToBinding; 19 | 20 | public SettingsData() 21 | { 22 | PropInpc = new SettingsPropInpcData(); 23 | FormatXaml = new SettingsFormatXamlData(); 24 | GoToBinding = new SettingsGoToBindingData(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: .NET 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: windows-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Setup .NET 21 | uses: actions/setup-dotnet@v4 22 | with: 23 | dotnet-version: 8.0.x 24 | 25 | - name: Restore dependencies 26 | run: dotnet restore 27 | 28 | - name: Build 29 | run: dotnet build --no-restore --configuration Release 30 | 31 | - name: Test 32 | run: dotnet test --no-build --configuration Release --verbosity normal 33 | 34 | - name: Upload VSIX artifact (BrightXaml) 35 | uses: actions/upload-artifact@v4 36 | with: 37 | name: vsix-artifact 38 | path: '**/BrightXaml*.vsix' -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ChooseItemWindowCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.Commands; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | /// 9 | /// A command for showing a tool window. 10 | /// 11 | [VisualStudioContribution] 12 | public class ChooseItemWindowCommand : Command 13 | { 14 | /// 15 | public override CommandConfiguration CommandConfiguration => new(displayName: "Show Item Chooser") 16 | { 17 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 18 | Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText), 19 | }; 20 | 21 | /// 22 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 23 | { 24 | await this.Extensibility.Shell().ShowToolWindowAsync(activate: true, cancellationToken); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Services/IDialogService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Extensibility.Shell; 2 | using Microsoft.VisualStudio.RpcContracts.Notifications; 3 | 4 | namespace BrightXaml.Extensibility.Services; 5 | public interface IDialogService 6 | { 7 | ShellExtensibility Shell { get; set; } 8 | 9 | Task ShowDialogOptionsAsync(string title, string label, List items, CancellationToken cancellationToken); 10 | 11 | Task ShowPromptOKAsync(string message, CancellationToken cancellationToken); 12 | Task ShowPromptOKCancelAsync(string message, CancellationToken cancellationToken); 13 | Task ShowPromptRetryCancelAsync(string message, CancellationToken cancellationToken); 14 | 15 | /// 16 | /// Only use this for a maximum of 5 items... It displays horizontally only. 17 | /// 18 | Task ShowPromptOptionsAsync(string title, List items, CancellationToken cancellationToken); 19 | 20 | Task ShowDialogProgressAsync(string message, out Action progress, CancellationToken cancellationToken); 21 | } -------------------------------------------------------------------------------- /BrightGit.SharpCommon/SharpRunHelper.cs: -------------------------------------------------------------------------------- 1 | using BrightGit.SharpCommon.Models; 2 | using System.Diagnostics; 3 | 4 | namespace BrightGit.SharpCommon; 5 | public class SharpRunHelper 6 | { 7 | public Action ActionMessageReceived { get; set; } 8 | 9 | private const string sharpRunFileName = "BrightGit.SharpRun.exe"; 10 | 11 | public void ExecuteGitAction(RunData data) 12 | { 13 | var processStartInfo = new ProcessStartInfo 14 | { 15 | FileName = sharpRunFileName, 16 | Arguments = $"{data.RunType} {data.RepoDir} {string.Join(" ", data.Parameters)}", 17 | RedirectStandardOutput = true, 18 | UseShellExecute = false, 19 | CreateNoWindow = true 20 | }; 21 | 22 | using (var process = Process.Start(processStartInfo)) 23 | { 24 | using (var reader = process.StandardOutput) 25 | { 26 | string result = reader.ReadToEnd(); 27 | 28 | // Raise event to notify the caller. 29 | ActionMessageReceived?.Invoke(result); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Luis Henrique Goll 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/TestHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace BrightXaml.ExtensibilityTests; 5 | internal static class TestHelper 6 | { 7 | internal static string ReadResource(string resourceName) 8 | { 9 | // Get the assembly where the resource is embedded. 10 | var assembly = Assembly.GetExecutingAssembly(); 11 | 12 | // Create the full resource name. 13 | string resourceFullName = assembly.GetName().Name + "." + resourceName; 14 | 15 | using (Stream stream = assembly.GetManifestResourceStream(resourceFullName)) 16 | { 17 | if (stream == null) 18 | { 19 | throw new InvalidOperationException("Resource not found: " + resourceFullName); 20 | } 21 | 22 | using (StreamReader reader = new StreamReader(stream)) 23 | { 24 | return reader.ReadToEnd(); 25 | } 26 | } 27 | } 28 | 29 | internal static void WriteTestResultToFile(string text, [CallerMemberName] string callerName = null) 30 | { 31 | File.WriteAllText(callerName + ".xaml", text); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ProgressWindowCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.Commands; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | /// 9 | /// A command for showing a tool window. 10 | /// 11 | [VisualStudioContribution] 12 | public class ProgressWindowCommand : Command 13 | { 14 | /// 15 | public override CommandConfiguration CommandConfiguration => new(displayName: "Progress Window") 16 | { 17 | // Use this object initializer to set optional parameters for the command. The required parameter, 18 | // displayName, is set above. To localize the displayName, add an entry in .vsextension\string-resources.json 19 | // and reference it here by passing "%BrightXaml.Extensibility.Windows.ProgressWindowCommand.DisplayName%" as a constructor parameter. 20 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 21 | Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText), 22 | }; 23 | 24 | /// 25 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 26 | { 27 | await this.Extensibility.Shell().ShowToolWindowAsync(activate: true, cancellationToken); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/BrightGit.Extensibility.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0-windows 4 | enable 5 | disable 6 | 7 | 8 | 9 | win-x64 10 | 11 | 1.0.0.0 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | MSBuild:Compile 20 | 21 | 22 | MSBuild:Compile 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/BrightXaml.Extensibility.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0-windows 4 | enable 5 | disable 6 | 7 | 1.2.0.0 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | MSBuild:Compile 18 | 19 | 20 | MSBuild:Compile 21 | 22 | 23 | MSBuild:Compile 24 | 25 | 26 | MSBuild:Compile 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /BrightGit.SharpHook/Program.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Pipes; 2 | 3 | namespace BrightGit.SharpHook; 4 | public class Program 5 | { 6 | static void Main(string[] args) 7 | { 8 | // The timeout for the connection to the pipe. 9 | const int timeout = 10000; 10 | 11 | // Skip the git hook to avoid entering an infinite loop. 12 | var skipVariable = Environment.GetEnvironmentVariable("BRIGHT_GITEFCORE_SKIP_GIT_HOOK"); 13 | if (skipVariable == "1") 14 | return; 15 | 16 | // First argument is the hook name, the rest are the arguments. 17 | if (args.Length < 1) 18 | { 19 | Console.WriteLine("Error, at least one argument is required (Example: `BrightGit.SharpHook.exe `."); 20 | return; 21 | } 22 | 23 | string eventName = args[0]; 24 | string arguments = string.Join("|", args, 1, args.Length - 1); 25 | 26 | using (var pipeClient = new NamedPipeClientStream(".", "BrightSharpHook", PipeDirection.Out)) 27 | { 28 | try 29 | { 30 | pipeClient.Connect(timeout); 31 | using (var writer = new StreamWriter(pipeClient)) 32 | { 33 | writer.AutoFlush = true; 34 | writer.WriteLine($"{eventName}|{arguments}"); 35 | } 36 | } 37 | catch (Exception ex) 38 | { 39 | Console.WriteLine($"Failed to send message: {ex.Message}"); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ProgressWindowContent.xaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Commands/ExtractViewCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Commands; 2 | 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using Microsoft.VisualStudio.Extensibility.Shell; 7 | using System.Diagnostics; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | [VisualStudioContribution] 12 | internal class ExtractViewCommand : Command 13 | { 14 | private readonly TraceSource logger; 15 | 16 | public ExtractViewCommand(TraceSource traceSource) 17 | { 18 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 19 | } 20 | 21 | /// 22 | public override CommandConfiguration CommandConfiguration => new(displayName: "Extract View + CodeBehind + ViewModel") 23 | { 24 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 25 | Shortcuts = [new CommandShortcutConfiguration(ModifierKey.Control, Key.E, ModifierKey.Control, Key.G)], 26 | Icon = new(ImageMoniker.KnownValues.ExportData, IconSettings.IconAndText), 27 | }; 28 | 29 | /// 30 | public override Task InitializeAsync(CancellationToken cancellationToken) 31 | { 32 | // Use InitializeAsync for any one-time setup or initialization. 33 | return base.InitializeAsync(cancellationToken); 34 | } 35 | 36 | /// 37 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 38 | { 39 | await this.Extensibility.Shell().ShowPromptAsync("Hello from Luis ;)", PromptOptions.OK, cancellationToken); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Services/DialogService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Extensibility.Shell; 2 | 3 | namespace BrightGit.Extensibility.Services; 4 | public class DialogService : IDialogService 5 | { 6 | public ShellExtensibility Shell { get; set; } 7 | 8 | public async Task ShowPromptOptionsAsync(string message, List items, CancellationToken cancellationToken) 9 | { 10 | if (message == null) 11 | message = "Choose:"; 12 | 13 | // Remove duplicates and sort the items. 14 | items = items.Distinct().ToList(); 15 | 16 | // Create a dictionary to map items to unique integers. 17 | Dictionary itemMap = new(); 18 | for (int i = 0; i < items.Count; i++) 19 | { 20 | itemMap[i] = items[i]; 21 | } 22 | 23 | // Create PromptOptions and populate it with the item map. 24 | var promptOptions = new PromptOptions 25 | { 26 | DismissedReturns = -1, 27 | DefaultChoiceIndex = 0, 28 | }; 29 | 30 | foreach (var kvp in itemMap) 31 | { 32 | promptOptions.Choices.Add(kvp.Value, kvp.Key); 33 | } 34 | 35 | // Show the prompt and get the result. 36 | var result = await Shell.ShowPromptAsync( 37 | message, 38 | promptOptions, 39 | cancellationToken); 40 | 41 | // Map the selected integer back to the corresponding item. 42 | if (itemMap.ContainsKey(result)) 43 | { 44 | return itemMap[result]; 45 | } 46 | 47 | // Return null or handle the case when no valid choice is made. 48 | return null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/HelpWindow.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.ToolWindows; 5 | using Microsoft.VisualStudio.RpcContracts.RemoteUI; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | /// 10 | /// A sample tool window. 11 | /// 12 | [VisualStudioContribution] 13 | public class HelpWindow : ToolWindow 14 | { 15 | private readonly HelpWindowContent content = new(); 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | public HelpWindow() 21 | { 22 | this.Title = "Bright Xaml - Help"; 23 | } 24 | 25 | /// 26 | public override ToolWindowConfiguration ToolWindowConfiguration => new() 27 | { 28 | // Use this object initializer to set optional parameters for the tool window. 29 | Placement = ToolWindowPlacement.Floating, 30 | }; 31 | 32 | /// 33 | public override Task InitializeAsync(CancellationToken cancellationToken) 34 | { 35 | // Use InitializeAsync for any one-time setup or initialization. 36 | return Task.CompletedTask; 37 | } 38 | 39 | /// 40 | public override Task GetContentAsync(CancellationToken cancellationToken) 41 | { 42 | return Task.FromResult(content); 43 | } 44 | 45 | /// 46 | protected override void Dispose(bool disposing) 47 | { 48 | if (disposing) 49 | content.Dispose(); 50 | 51 | base.Dispose(disposing); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Helpers/VSHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Extensibility; 2 | using Microsoft.VisualStudio.ProjectSystem.Query; 3 | 4 | namespace BrightGit.Extensibility.Helpers; 5 | public static class VSHelper 6 | { 7 | public static async Task GetSolutionPathAsync(WorkspacesExtensibility workspace, CancellationToken cancellationToken) 8 | { 9 | // Get the solution path. 10 | var solutionPath = (await workspace.QuerySolutionAsync(solution => solution.With(p => p.Path), cancellationToken)).FirstOrDefault()?.Path; 11 | return solutionPath; 12 | } 13 | 14 | public static async Task GetSolutionNameAsync(WorkspacesExtensibility workspace, CancellationToken cancellationToken) 15 | { 16 | return Path.GetFileNameWithoutExtension(await GetSolutionPathAsync(workspace, cancellationToken)); 17 | } 18 | 19 | public static async Task GetSolutionDirectoryAsync(WorkspacesExtensibility workspace, CancellationToken cancellationToken) 20 | { 21 | // Get the solution directory. 22 | var solutionDirectory = (await workspace.QuerySolutionAsync(solution => solution.With(p => p.Directory), cancellationToken)).FirstOrDefault()?.Directory; 23 | return solutionDirectory; 24 | } 25 | 26 | public static async Task> GetProjectsDirectoryAsync(WorkspacesExtensibility workspace, CancellationToken cancellationToken) 27 | { 28 | // Get the directories from all active projects in the solution. 29 | var projectsDirs = await workspace.QuerySolutionAsync(solution => solution.Get(p => p.Projects).With(p => p.Path), cancellationToken); 30 | return projectsDirs.Select(p => p.Path).ToList(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Commands/ShowViewCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Commands; 2 | 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using Microsoft.VisualStudio.Extensibility.Shell; 7 | using System.Diagnostics; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | [VisualStudioContribution] 12 | internal class ShowViewCommand : Command 13 | { 14 | private readonly TraceSource logger; 15 | 16 | public ShowViewCommand(TraceSource traceSource) 17 | { 18 | logger = Requires.NotNull(traceSource, nameof(traceSource)); 19 | } 20 | 21 | /// 22 | public override CommandConfiguration CommandConfiguration => new(displayName: "Show View (Ctrl+E+1)") 23 | { 24 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 25 | Shortcuts = [new CommandShortcutConfiguration(ModifierKey.Control, Key.E, ModifierKey.Control, Key.VK_NUMPAD1)], 26 | Icon = new(ImageMoniker.KnownValues.View, IconSettings.IconAndText), 27 | TooltipText = "Shows the View of the current ViewModel", 28 | }; 29 | 30 | /// 31 | public override Task InitializeAsync(CancellationToken cancellationToken) 32 | { 33 | // Use InitializeAsync for any one-time setup or initialization. 34 | return base.InitializeAsync(cancellationToken); 35 | } 36 | 37 | /// 38 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 39 | { 40 | await Extensibility.Shell().ShowPromptAsync("Hello from an extension!", PromptOptions.OK, cancellationToken); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Helpers/VSHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Extensibility; 2 | using Microsoft.VisualStudio.ProjectSystem.Query; 3 | 4 | namespace BrightXaml.Extensibility.Helpers; 5 | public static class VSHelper 6 | { 7 | public static async Task GetSolutionPathAsync(WorkspacesExtensibility workspace, CancellationToken cancellationToken) 8 | { 9 | // Get the solution path. 10 | var solutionPath = (await workspace.QuerySolutionAsync(solution => solution.With(p => p.Path), cancellationToken)).FirstOrDefault()?.Path; 11 | return solutionPath; 12 | } 13 | 14 | public static async Task GetSolutionNameAsync(WorkspacesExtensibility workspace, CancellationToken cancellationToken) 15 | { 16 | return Path.GetFileNameWithoutExtension(await GetSolutionPathAsync(workspace, cancellationToken)); 17 | } 18 | 19 | public static async Task GetSolutionDirectoryAsync(WorkspacesExtensibility workspace, CancellationToken cancellationToken) 20 | { 21 | // Get the solution directory. 22 | var solutionDirectory = (await workspace.QuerySolutionAsync(solution => solution.With(p => p.Directory), cancellationToken)).FirstOrDefault()?.Directory; 23 | return solutionDirectory; 24 | } 25 | 26 | public static async Task> GetProjectsDirectoryAsync(WorkspacesExtensibility workspace, CancellationToken cancellationToken) 27 | { 28 | // Get the directories from all active projects in the solution. 29 | var projectsDirs = await workspace.QuerySolutionAsync(solution => solution.Get(p => p.Projects).With(p => p.Path), cancellationToken); 30 | return projectsDirs.Select(p => p.Path).ToList(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ChooseItemWindowContent.xaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ProgressWindow.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.ToolWindows; 5 | using Microsoft.VisualStudio.RpcContracts.RemoteUI; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | /// 10 | /// A sample tool window. 11 | /// 12 | [VisualStudioContribution] 13 | public class ProgressWindow : ToolWindow 14 | { 15 | private readonly ProgressWindowContent content = new(); 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | public ProgressWindow() 21 | { 22 | this.Title = "Progress Window"; 23 | } 24 | 25 | /// 26 | public override ToolWindowConfiguration ToolWindowConfiguration => new() 27 | { 28 | // Use this object initializer to set optional parameters for the tool window. 29 | Placement = ToolWindowPlacement.Floating, 30 | }; 31 | 32 | /// 33 | public override Task InitializeAsync(CancellationToken cancellationToken) 34 | { 35 | // Use InitializeAsync for any one-time setup or initialization. 36 | return Task.CompletedTask; 37 | } 38 | 39 | /// 40 | public override Task GetContentAsync(CancellationToken cancellationToken) 41 | { 42 | return Task.FromResult(content); 43 | } 44 | 45 | /// 46 | protected override void Dispose(bool disposing) 47 | { 48 | if (disposing) 49 | content.Dispose(); 50 | 51 | base.Dispose(disposing); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/ChooseItemWindow.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using Microsoft.VisualStudio.Extensibility; 4 | using Microsoft.VisualStudio.Extensibility.ToolWindows; 5 | using Microsoft.VisualStudio.RpcContracts.RemoteUI; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | /// 10 | /// A sample tool window. 11 | /// 12 | [VisualStudioContribution] 13 | public class ChooseItemWindow : ToolWindow 14 | { 15 | private readonly ChooseItemWindowContent content = new(); 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | public ChooseItemWindow() 21 | { 22 | this.Title = "My Tool Window"; 23 | } 24 | 25 | /// 26 | public override ToolWindowConfiguration ToolWindowConfiguration => new() 27 | { 28 | // Use this object initializer to set optional parameters for the tool window. 29 | Placement = ToolWindowPlacement.Floating, 30 | }; 31 | 32 | /// 33 | public override Task InitializeAsync(CancellationToken cancellationToken) 34 | { 35 | // Use InitializeAsync for any one-time setup or initialization. 36 | return Task.CompletedTask; 37 | } 38 | 39 | /// 40 | public override Task GetContentAsync(CancellationToken cancellationToken) 41 | { 42 | return Task.FromResult(content); 43 | } 44 | 45 | /// 46 | protected override void Dispose(bool disposing) 47 | { 48 | if (disposing) 49 | content.Dispose(); 50 | 51 | base.Dispose(disposing); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Services/SettingsPropInpcData.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Runtime.Serialization; 3 | 4 | namespace BrightXaml.Extensibility.Services; 5 | [DataContract] 6 | public class SettingsPropInpcData : ObservableObject 7 | { 8 | [DataMember] 9 | public bool IsEnabled { get => isEnabled; set => SetProperty(ref isEnabled, value); } 10 | private bool isEnabled = true; 11 | 12 | [DataMember] 13 | public bool UseFieldKeyword { get => useFieldKeyword; set => SetProperty(ref useFieldKeyword, value); } 14 | private bool useFieldKeyword = false; 15 | 16 | [DataMember] 17 | public bool UseObservableProperty { get => useObservableProperty; set => SetProperty(ref useObservableProperty, value); } 18 | private bool useObservableProperty = false; 19 | 20 | [DataMember] 21 | public bool UseBackingField { get => useBackingField; set => SetProperty(ref useBackingField, value); } 22 | private bool useBackingField = true; 23 | 24 | [DataMember] 25 | public bool AddFieldAbove { get => addFieldAbove; set => SetProperty(ref addFieldAbove, value); } 26 | private bool addFieldAbove = false; 27 | 28 | [DataMember] 29 | public bool AddFieldUnderscore { get => addFieldUnderscore; set => SetProperty(ref addFieldUnderscore, value); } 30 | private bool addFieldUnderscore = false; 31 | 32 | [DataMember] 33 | public string SetMethodName { get => setMethodName; set => SetProperty(ref setMethodName, value); } 34 | private string setMethodName = "SetProperty"; 35 | 36 | [DataMember] 37 | public bool PreserveDefaultValue { get => preserveDefaultValue; set => SetProperty(ref preserveDefaultValue, value); } 38 | private bool preserveDefaultValue = true; 39 | } -------------------------------------------------------------------------------- /BrightGit.Extensibility/Services/SettingsService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text.Json; 3 | 4 | namespace BrightGit.Extensibility.Services; 5 | public class SettingsService 6 | { 7 | private const string fileName = "BrightGitSettings.json"; 8 | private readonly string directory; 9 | private readonly string filePath; 10 | 11 | public SettingsData Data { get; set; } = new(); 12 | 13 | public SettingsService() 14 | { 15 | directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "BrightExtensions"); 16 | filePath = Path.Combine(directory, fileName); 17 | Load(); 18 | } 19 | 20 | public void Load() 21 | { 22 | try 23 | { 24 | // Check if directory exists. 25 | if (!Directory.Exists(directory)) 26 | Directory.CreateDirectory(directory); 27 | 28 | // Load settings. 29 | if (File.Exists(filePath)) 30 | { 31 | var json = File.ReadAllText(filePath); 32 | Data = JsonSerializer.Deserialize(json) ?? new SettingsData(); 33 | } 34 | } 35 | catch (Exception ex) 36 | { 37 | Debug.WriteLine(ex); 38 | 39 | // Use default settings. 40 | Data = new SettingsData(); 41 | } 42 | } 43 | 44 | public void Save() 45 | { 46 | try 47 | { 48 | var json = JsonSerializer.Serialize(Data, new JsonSerializerOptions { WriteIndented = true }); 49 | File.WriteAllText(filePath, json); 50 | } 51 | catch (Exception ex) 52 | { 53 | // Add log? 54 | Debug.WriteLine(ex); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /BrightGit.Extensibility/Listeners/GitSharpHookListener.cs: -------------------------------------------------------------------------------- 1 | using BrightGit.Extensibility.Services; 2 | using Microsoft.VisualStudio.Extensibility; 3 | using Microsoft.VisualStudio.Extensibility.Editor; 4 | using System.Diagnostics; 5 | 6 | namespace BrightGit.Extensibility.Listeners; 7 | [VisualStudioContribution] 8 | public class GitSharpHookListener : ExtensionPart, ITextViewOpenClosedListener, ITextViewChangedListener 9 | { 10 | public TextViewExtensionConfiguration TextViewExtensionConfiguration => new() 11 | { 12 | AppliesTo = 13 | [ 14 | DocumentFilter.FromGlobPattern("**/*", true), 15 | ], 16 | }; 17 | 18 | public GitSharpHookListener(TraceSource traceSource, SettingsService settingsService, GitSharpHookService gitSharpHookService) 19 | { 20 | // If any of the features are enabled, we need to listen for Git hooks. 21 | if (settingsService.Data.Tabs.IsEnabled || settingsService.Data.EFCore.IsEnabled) 22 | { 23 | // TODO: 24 | // Disabled at the moment as I'm experimenting with FileWatcherService. 25 | //_ = gitSharpHookService.StartMonitoringAsync(); 26 | } 27 | } 28 | 29 | // We inherit from Listeners just to trigger our constructor and start monitoring git events. 30 | public Task TextViewChangedAsync(TextViewChangedArgs args, CancellationToken cancellationToken) 31 | { 32 | return Task.CompletedTask; 33 | } 34 | 35 | public Task TextViewClosedAsync(ITextViewSnapshot textView, CancellationToken cancellationToken) 36 | { 37 | return Task.CompletedTask; 38 | } 39 | 40 | public Task TextViewOpenedAsync(ITextViewSnapshot textView, CancellationToken cancellationToken) 41 | { 42 | return Task.CompletedTask; 43 | } 44 | } -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Commands/DevOpenSolutionCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Commands; 2 | 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using System.Diagnostics; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | [VisualStudioContribution] 11 | internal class DevOpenSolutionCommand : Command 12 | { 13 | private readonly TraceSource logger; 14 | 15 | public DevOpenSolutionCommand(TraceSource traceSource) 16 | { 17 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 18 | } 19 | 20 | /// 21 | public override CommandConfiguration CommandConfiguration => new(displayName: "Dev Open Test Solution") 22 | { 23 | #if DEBUG 24 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 25 | //Shortcuts = [new CommandShortcutConfiguration(ModifierKey.Control, Key.E, ModifierKey.Control, Key.T)], 26 | #endif 27 | Icon = new(ImageMoniker.KnownValues.DebugTemplate, IconSettings.IconAndText), 28 | }; 29 | 30 | /// 31 | public override Task InitializeAsync(CancellationToken cancellationToken) 32 | { 33 | // Use InitializeAsync for any one-time setup or initialization. 34 | return base.InitializeAsync(cancellationToken); 35 | } 36 | 37 | /// 38 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 39 | { 40 | // TODO: Open a solution for testing. 41 | // TODO: This opens the file, not the solution itself... 42 | await this.Extensibility.Documents().OpenDocumentAsync(new Uri(@"D:\Projects Visual Studio\Test Projects\TestWPFNETCore\TestWPFNETCore.sln"), cancellationToken); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Services/SettingsService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text.Json; 3 | 4 | namespace BrightXaml.Extensibility.Services; 5 | public class SettingsService 6 | { 7 | private const string settingsFileName = "BrightXamlSettings.json"; 8 | private readonly string settingsDirectory; 9 | private readonly string settingsFilePath; 10 | 11 | public SettingsData Data { get; set; } = new(); 12 | 13 | public SettingsService() 14 | { 15 | settingsDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "BrightExtensions"); 16 | settingsFilePath = Path.Combine(settingsDirectory, settingsFileName); 17 | Load(); 18 | } 19 | 20 | public void Load() 21 | { 22 | try 23 | { 24 | // Check if directory exists. 25 | if (!Directory.Exists(settingsDirectory)) 26 | Directory.CreateDirectory(settingsDirectory); 27 | 28 | // Load settings. 29 | if (File.Exists(settingsFilePath)) 30 | { 31 | var json = File.ReadAllText(settingsFilePath); 32 | Data = JsonSerializer.Deserialize(json) ?? new SettingsData(); 33 | } 34 | } 35 | catch (Exception ex) 36 | { 37 | Debug.WriteLine(ex); 38 | 39 | // Use default settings. 40 | Data = new SettingsData(); 41 | } 42 | } 43 | 44 | public void Save() 45 | { 46 | try 47 | { 48 | var json = JsonSerializer.Serialize(Data, new JsonSerializerOptions { WriteIndented = true }); 49 | File.WriteAllText(settingsFilePath, json); 50 | } 51 | catch (Exception ex) 52 | { 53 | // Add log? 54 | Debug.WriteLine(ex); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Commands/ShowCodeBehindCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Commands; 2 | 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using Microsoft.VisualStudio.Extensibility.Shell; 7 | using System.Diagnostics; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | [VisualStudioContribution] 12 | internal class ShowCodeBehindCommand : Command 13 | { 14 | private readonly TraceSource logger; 15 | 16 | public ShowCodeBehindCommand(TraceSource traceSource) 17 | { 18 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 19 | } 20 | 21 | /// 22 | public override CommandConfiguration CommandConfiguration => new(displayName: "Show CodeBehind (Ctrl+E+3)") 23 | { 24 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 25 | Shortcuts = [new CommandShortcutConfiguration(ModifierKey.Control, Key.E, ModifierKey.Control, Key.VK_NUMPAD3)], 26 | Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText), 27 | EnabledWhen = ActivationConstraint.ClientContext(ClientContextKey.Shell.ActiveEditorContentType, ".+"), 28 | TooltipText = "Shows the CodeBehind of the current View or ViewModel", 29 | }; 30 | 31 | /// 32 | public override Task InitializeAsync(CancellationToken cancellationToken) 33 | { 34 | // Use InitializeAsync for any one-time setup or initialization. 35 | return base.InitializeAsync(cancellationToken); 36 | } 37 | 38 | /// 39 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 40 | { 41 | await this.Extensibility.Shell().ShowPromptAsync("Hello from Luis :)", PromptOptions.OK, cancellationToken); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Windows/TabsWindow.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Windows; 2 | 3 | using BrightGit.Extensibility.Services; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.ToolWindows; 6 | using Microsoft.VisualStudio.RpcContracts.RemoteUI; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | /// 11 | /// A sample tool window. 12 | /// 13 | [VisualStudioContribution] 14 | public class TabsWindow : ToolWindow 15 | { 16 | private readonly TabsWindowContent content; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | public TabsWindow(TabsStorageService tabsStorageService) 22 | { 23 | this.Title = "Bright Git - Tabs"; 24 | this.content = new TabsWindowContent(tabsStorageService); 25 | content.ViewModel.CloseWindow = (cancellationToken) => { _ = HideAsync(cancellationToken); }; 26 | } 27 | 28 | /// 29 | public override ToolWindowConfiguration ToolWindowConfiguration => new() 30 | { 31 | // Use this object initializer to set optional parameters for the tool window. 32 | Placement = ToolWindowPlacement.Floating, 33 | }; 34 | 35 | /// 36 | public override Task InitializeAsync(CancellationToken cancellationToken) 37 | { 38 | // Use InitializeAsync for any one-time setup or initialization. 39 | return Task.CompletedTask; 40 | } 41 | 42 | /// 43 | public override Task GetContentAsync(CancellationToken cancellationToken) 44 | { 45 | return Task.FromResult(content); 46 | } 47 | 48 | /// 49 | protected override void Dispose(bool disposing) 50 | { 51 | if (disposing) 52 | content.Dispose(); 53 | 54 | base.Dispose(disposing); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Commands/KillXamlDesignerCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Commands; 2 | 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using System.Diagnostics; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | [VisualStudioContribution] 11 | internal class KillXamlDesignerCommand : Command 12 | { 13 | private readonly TraceSource logger; 14 | 15 | public KillXamlDesignerCommand(TraceSource traceSource) 16 | { 17 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 18 | } 19 | 20 | /// 21 | public override CommandConfiguration CommandConfiguration => new(displayName: "Kill XAML Designer Process") 22 | { 23 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 24 | Icon = new(ImageMoniker.KnownValues.TerminateProcess, IconSettings.IconAndText), 25 | }; 26 | 27 | /// 28 | public override Task InitializeAsync(CancellationToken cancellationToken) 29 | { 30 | // Use InitializeAsync for any one-time setup or initialization. 31 | return base.InitializeAsync(cancellationToken); 32 | } 33 | 34 | /// 35 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 36 | { 37 | KillAllDesigners(); 38 | await Task.CompletedTask; 39 | } 40 | 41 | private static void KillAllDesigners() 42 | { 43 | // VS 2022. 44 | var designers = Process.GetProcessesByName("WpfSurface"); 45 | foreach (var designer in designers) 46 | { 47 | designer.Kill(); 48 | } 49 | 50 | // Usually up to VS 2019. 51 | //var designers = Process.GetProcessesByName("XDesProc"); 52 | //foreach (var designer in designers) 53 | //{ 54 | // designer.Kill(); 55 | //} 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Windows/SettingsWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Windows; 2 | 3 | using BrightGit.Extensibility.Services; 4 | using Microsoft.VisualStudio.Extensibility.UI; 5 | using System.Runtime.Serialization; 6 | using System.Text.Json; 7 | 8 | [DataContract] 9 | internal class SettingsWindowViewModel : NotifyPropertyChangedObject 10 | { 11 | public Action CloseWindow { get; set; } 12 | 13 | public SettingsService SettingsService { get; } 14 | 15 | [DataMember] 16 | public SettingsData SettingsData { get => settingsData; private set => SetProperty(ref settingsData, value); } 17 | private SettingsData settingsData; 18 | 19 | [DataMember] 20 | public AsyncCommand OKCommand { get; } 21 | 22 | [DataMember] 23 | public AsyncCommand CancelCommand { get; } 24 | 25 | [DataMember] 26 | public string Version { get; } = Meta.Version.ToString(); 27 | 28 | public SettingsWindowViewModel(SettingsService settingsService) 29 | { 30 | SettingsService = settingsService; 31 | SettingsData = CloneSettings(settingsService.Data); 32 | 33 | OKCommand = new AsyncCommand((parameter, clientContext, cancellationToken) => 34 | { 35 | // Save settings. 36 | SaveSettings(); 37 | 38 | // Close window. 39 | CloseWindow?.Invoke(cancellationToken); 40 | return Task.CompletedTask; 41 | }); 42 | CancelCommand = new AsyncCommand((parameter, clientContext, cancellationToken) => 43 | { 44 | // Reset settings. 45 | SettingsData = CloneSettings(settingsService.Data); 46 | 47 | // Close window. 48 | CloseWindow?.Invoke(cancellationToken); 49 | return Task.CompletedTask; 50 | }); 51 | } 52 | 53 | public void SaveSettings() 54 | { 55 | SettingsService.Data = SettingsData; 56 | SettingsService.Save(); 57 | } 58 | 59 | public SettingsData CloneSettings(SettingsData data) 60 | { 61 | return JsonSerializer.Deserialize(JsonSerializer.Serialize(data)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Commands/ExtractClassesInUseCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Commands; 2 | 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using Microsoft.VisualStudio.Extensibility.Shell; 7 | using System.Diagnostics; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | [VisualStudioContribution] 12 | internal class ExtractClassesInUseCommand : Command 13 | { 14 | private readonly TraceSource logger; 15 | 16 | public ExtractClassesInUseCommand(TraceSource traceSource) 17 | { 18 | logger = Requires.NotNull(traceSource, nameof(traceSource)); 19 | } 20 | 21 | /// 22 | public override CommandConfiguration CommandConfiguration => new(displayName: "[WIP] Export Referenced Classes") 23 | { 24 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 25 | Icon = new(ImageMoniker.KnownValues.ExportData, IconSettings.IconAndText), 26 | //Shortcuts = [new CommandShortcutConfiguration(ModifierKey.Control, Key.E, ModifierKey.Control, Key.H)], 27 | EnabledWhen = ActivationConstraint.ClientContext(ClientContextKey.Shell.ActiveEditorFileName, @"\.(cs)$"), 28 | TooltipText = "Copies to clipboard all classes being used in the current document", 29 | }; 30 | 31 | /// 32 | public override Task InitializeAsync(CancellationToken cancellationToken) 33 | { 34 | // Use InitializeAsync for any one-time setup or initialization. 35 | return base.InitializeAsync(cancellationToken); 36 | } 37 | 38 | /// 39 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 40 | { 41 | var shell = Extensibility.Shell(); 42 | var workspace = Extensibility.Workspaces(); 43 | var documents = Extensibility.Documents(); 44 | 45 | await Extensibility.Shell().ShowPromptAsync("Work in Progress!", PromptOptions.OK, cancellationToken); 46 | } 47 | 48 | public void CopyClassesToClipboard(string text) 49 | { 50 | if (!string.IsNullOrWhiteSpace(text)) 51 | { 52 | 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Windows/TabsWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Windows; 2 | 3 | using BrightGit.Extensibility.Services; 4 | using Microsoft.VisualStudio.Extensibility.UI; 5 | using System.Runtime.Serialization; 6 | using System.Text.Json; 7 | 8 | [DataContract] 9 | internal class TabsWindowViewModel : NotifyPropertyChangedObject 10 | { 11 | public Action CloseWindow { get; set; } 12 | 13 | [DataMember] 14 | public TabsStorageData TabsStorageData { get => tabsStorageData; private set => SetProperty(ref tabsStorageData, value); } 15 | private TabsStorageData tabsStorageData; 16 | 17 | [DataMember] 18 | public AsyncCommand OKCommand { get; } 19 | 20 | [DataMember] 21 | public AsyncCommand CancelCommand { get; } 22 | 23 | [DataMember] 24 | public string Version { get; } = Meta.Version.ToString(); 25 | 26 | private readonly TabsStorageService tabsStorageService; 27 | 28 | public TabsWindowViewModel(TabsStorageService tabsStorageService) 29 | { 30 | TabsStorageData = CloneTabsStorage(tabsStorageService.Data); 31 | 32 | OKCommand = new AsyncCommand((parameter, clientContext, cancellationToken) => 33 | { 34 | // Save TabsStorage. 35 | SaveTabsStorage(); 36 | 37 | // Close window. 38 | CloseWindow?.Invoke(cancellationToken); 39 | return Task.CompletedTask; 40 | }); 41 | CancelCommand = new AsyncCommand((parameter, clientContext, cancellationToken) => 42 | { 43 | // Reset TabsStorage. 44 | TabsStorageData = CloneTabsStorage(tabsStorageService.Data); 45 | 46 | // Close window. 47 | CloseWindow?.Invoke(cancellationToken); 48 | return Task.CompletedTask; 49 | }); 50 | 51 | this.tabsStorageService = tabsStorageService; 52 | } 53 | 54 | public void SaveTabsStorage() 55 | { 56 | tabsStorageService.Data = TabsStorageData; 57 | tabsStorageService.Save(); 58 | } 59 | 60 | public TabsStorageData CloneTabsStorage(TabsStorageData data) 61 | { 62 | return JsonSerializer.Deserialize(JsonSerializer.Serialize(data)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Commands/HelloWorldCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Commands; 2 | 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using Microsoft.VisualStudio.Extensibility.Shell; 7 | using System.Diagnostics; 8 | 9 | /// 10 | /// Command1 handler. 11 | /// 12 | [VisualStudioContribution] 13 | internal class HelloWorldCommand : Command 14 | { 15 | private readonly TraceSource logger; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// Trace source instance to utilize. 21 | public HelloWorldCommand(TraceSource traceSource) 22 | { 23 | // This optional TraceSource can be used for logging in the command. You can use dependency injection to access 24 | // other services here as well. 25 | logger = Requires.NotNull(traceSource, nameof(traceSource)); 26 | } 27 | 28 | /// 29 | public override CommandConfiguration CommandConfiguration => new("%BrightXaml.Extensibility.HelloWorldCommand.DisplayName%") 30 | { 31 | // Use this object initializer to set optional parameters for the command. The required parameter, 32 | // displayName, is set above. DisplayName is localized and references an entry in .vsextension\string-resources.json. 33 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 34 | Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText), 35 | TooltipText = "Shows a prompt with a hello message (Debug/Test Only)", 36 | }; 37 | 38 | /// 39 | public override Task InitializeAsync(CancellationToken cancellationToken) 40 | { 41 | // Use InitializeAsync for any one-time setup or initialization. 42 | return base.InitializeAsync(cancellationToken); 43 | } 44 | 45 | /// 46 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 47 | { 48 | await Extensibility.Shell().ShowPromptAsync("Hello from Luis' extension!", PromptOptions.OK, cancellationToken); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /BrightXaml.ExtensibilityTests/Utilities/ViewModelHelperTests.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Utilities.Tests; 2 | 3 | [TestClass()] 4 | public class ViewModelHelperTests 5 | { 6 | [TestMethod()] 7 | [DataRow("Main", "MainViewModel.cs")] 8 | [DataRow("MainPage", "MainViewModel.cs")] 9 | [DataRow("MainPage", "MainPageViewModel.cs")] 10 | [DataRow("MainWindow", "MainViewModel.cs")] 11 | [DataRow("MainWindow", "MainWindowViewModel.cs")] 12 | [DataRow("MyNiceMvvmClientViewEdit", "MyNiceMvvmClientViewEditViewModel.cs")] 13 | [DataRow("ChooseItemWindowContent", "ChooseItemWindowViewModel.cs")] 14 | public void GetViewModelNamePossibilitiesTest(string xamlName, string expected) 15 | { 16 | var possibilities = ViewModelHelper.GetViewModelNamePossibilities(xamlName); 17 | Assert.IsTrue(possibilities.Contains(expected)); 18 | } 19 | 20 | [TestMethod()] 21 | [DataRow("MainViewModel", "MainView.xaml")] 22 | [DataRow("MainViewModel", "MainPage.xaml")] 23 | [DataRow("MainViewModel", "MainWindow.xaml")] 24 | [DataRow("MainViewModel", "Main.xaml")] 25 | [DataRow("MainWindowViewModel", "MainWindowContent.xaml")] 26 | public void GetViewNamePossibilitiesTest(string viewModelName, string expected) 27 | { 28 | var possibilities = ViewModelHelper.GetViewNamePossibilities(viewModelName); 29 | Assert.IsTrue(possibilities.Contains(expected)); 30 | } 31 | 32 | [TestMethod()] 33 | public void RemoveCommonPathTest() 34 | { 35 | // Arrange 36 | List filePaths = new List 37 | { 38 | "C:/test/my/project/test.cs", 39 | "C:/test/my/project/test2.cs", 40 | "C:/test/my/project/test.cs", 41 | "C:/test/my/project2/test2.cs", 42 | "C:/test/my2/project/test.cs" 43 | }; 44 | 45 | List expected = new List 46 | { 47 | "my/project/test.cs", 48 | "my/project/test2.cs", 49 | "my/project/test.cs", 50 | "my/project2/test2.cs", 51 | "my2/project/test.cs" 52 | }; 53 | 54 | // Act 55 | List result = ViewModelHelper.RemoveCommonPath(filePaths); 56 | 57 | // Assert 58 | CollectionAssert.AreEqual(expected, result); 59 | } 60 | } -------------------------------------------------------------------------------- /BrightGit.Extensibility/Commands/EFGitTest.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Commands; 2 | using LibGit2Sharp; 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using Microsoft.VisualStudio.Extensibility.Shell; 7 | using System.Diagnostics; 8 | using System.Reflection; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | [VisualStudioContribution] 13 | internal class EFGitTest : Command 14 | { 15 | private readonly TraceSource logger; 16 | 17 | public EFGitTest(TraceSource traceSource) 18 | { 19 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 20 | } 21 | 22 | /// 23 | public override CommandConfiguration CommandConfiguration => new(displayName: "(Dev) EF Core - Test Git Library") 24 | { 25 | // Use in debug only for testing, might be deleted later. 26 | #if DEBUG 27 | Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 28 | #endif 29 | Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText), 30 | }; 31 | 32 | /// 33 | public override Task InitializeAsync(CancellationToken cancellationToken) 34 | { 35 | // Use InitializeAsync for any one-time setup or initialization. 36 | return base.InitializeAsync(cancellationToken); 37 | } 38 | 39 | /// 40 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 41 | { 42 | try 43 | { 44 | // Set the native library path for LibGit2Sharp when inside VS extension (VSIX). 45 | string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 46 | assemblyFolder = assemblyFolder[..^2]; 47 | GlobalSettings.NativeLibraryPath = Path.Combine(assemblyFolder, "runtimes", "win-x64", "native"); 48 | 49 | var repo = new Repository(""); 50 | await Extensibility.Shell().ShowPromptAsync("Success", PromptOptions.OK, cancellationToken); 51 | } 52 | catch (Exception ex) 53 | { 54 | logger.TraceEvent(TraceEventType.Error, 0, ex.Message); 55 | await Extensibility.Shell().ShowPromptAsync(ex.Message, PromptOptions.OK, cancellationToken); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /BrightGit.SharpCommon/Helpers/MigratorHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace BrightGit.SharpCommon.Helpers; 4 | public static class MigratorHelper 5 | { 6 | public static List FindMigrationsInDir(string migrationDir) 7 | { 8 | // Get all .cs files in the Migrations directory (excluding .designer.cs). 9 | var migrations = Directory.GetFiles(migrationDir) 10 | .Where(p => p.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) && 11 | !p.EndsWith(".designer.cs", StringComparison.OrdinalIgnoreCase)) 12 | .OrderBy(p => p) 13 | .ToList(); 14 | 15 | // Check only for .cs files containing this specific date format (a real migration). 16 | string dateformat = "yyyyMMddHHmmss"; 17 | migrations.RemoveAll(migration => !DateTime.TryParseExact(Path.GetFileName(migration)[..14], dateformat, CultureInfo.InvariantCulture, DateTimeStyles.None, out _)); 18 | 19 | return migrations; 20 | } 21 | 22 | public static string GetLatestCommonNameBetweenTwoLists(List list1, List list2) 23 | { 24 | // Get the latest common name between two lists. 25 | return list1.Intersect(list2).LastOrDefault(); 26 | } 27 | 28 | public static string GetMigrationsDirectory(string repoDir) 29 | { 30 | // Check if the repoDir exists. 31 | if (!Directory.Exists(repoDir)) 32 | return null; 33 | 34 | // Search for the Migrations directory. 35 | var directories = Directory.GetDirectories(repoDir, "Migrations", SearchOption.AllDirectories); 36 | 37 | // Return the first found Migrations directory, or null if not found. 38 | return directories.Length > 0 ? directories[0] : null; 39 | } 40 | 41 | public static string GetProjectFilePathFromInsideOut(string childrDir) 42 | { 43 | string currentDir = childrDir; 44 | 45 | while (currentDir != null) 46 | { 47 | var projectFile = Directory.GetFiles(currentDir, "*.csproj").FirstOrDefault(); 48 | if (projectFile != null) 49 | return projectFile; 50 | 51 | currentDir = Directory.GetParent(currentDir)?.FullName; 52 | } 53 | 54 | return null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Windows/SettingsWindow.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Windows; 2 | 3 | using BrightGit.Extensibility.Services; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.ToolWindows; 6 | using Microsoft.VisualStudio.RpcContracts.RemoteUI; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | /// 11 | /// A sample tool window. 12 | /// 13 | [VisualStudioContribution] 14 | public class SettingsWindow : ToolWindow 15 | { 16 | private readonly SettingsWindowContent content; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | public SettingsWindow(SettingsService settingsService) 22 | { 23 | this.Title = "Bright Git - Settings"; 24 | this.content = new SettingsWindowContent(settingsService); 25 | content.ViewModel.CloseWindow = (cancellationToken) => { _ = HideAsync(cancellationToken); }; 26 | } 27 | 28 | /// 29 | public override ToolWindowConfiguration ToolWindowConfiguration => new() 30 | { 31 | // Use this object initializer to set optional parameters for the tool window. 32 | Placement = ToolWindowPlacement.Floating, 33 | }; 34 | 35 | /// 36 | public override Task InitializeAsync(CancellationToken cancellationToken) 37 | { 38 | // Use InitializeAsync for any one-time setup or initialization. 39 | return Task.CompletedTask; 40 | } 41 | 42 | /// 43 | public override Task GetContentAsync(CancellationToken cancellationToken) 44 | { 45 | return Task.FromResult(content); 46 | } 47 | 48 | public override Task OnShowAsync(CancellationToken cancellationToken) 49 | { 50 | return base.OnShowAsync(cancellationToken); 51 | } 52 | 53 | public override Task OnHideAsync(CancellationToken cancellationToken) 54 | { 55 | // Auto save when closing? 56 | //content.ViewModel.SaveSettings(); 57 | return base.OnHideAsync(cancellationToken); 58 | } 59 | 60 | /// 61 | protected override void Dispose(bool disposing) 62 | { 63 | if (disposing) 64 | content.Dispose(); 65 | 66 | base.Dispose(disposing); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/SettingsWindow.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using BrightXaml.Extensibility.Services; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.ToolWindows; 6 | using Microsoft.VisualStudio.RpcContracts.RemoteUI; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | /// 11 | /// A sample tool window. 12 | /// 13 | [VisualStudioContribution] 14 | public class SettingsWindow : ToolWindow 15 | { 16 | private readonly SettingsWindowContent content; 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | public SettingsWindow(SettingsService settingsService) 22 | { 23 | this.Title = "Bright Xaml - Settings"; 24 | this.content = new SettingsWindowContent(settingsService); 25 | content.ViewModel.CloseWindow = (cancellationToken) => { _ = HideAsync(cancellationToken); }; 26 | } 27 | 28 | /// 29 | public override ToolWindowConfiguration ToolWindowConfiguration => new() 30 | { 31 | // Use this object initializer to set optional parameters for the tool window. 32 | Placement = ToolWindowPlacement.Floating, 33 | }; 34 | 35 | /// 36 | public override Task InitializeAsync(CancellationToken cancellationToken) 37 | { 38 | // Use InitializeAsync for any one-time setup or initialization. 39 | return Task.CompletedTask; 40 | } 41 | 42 | /// 43 | public override Task GetContentAsync(CancellationToken cancellationToken) 44 | { 45 | return Task.FromResult(content); 46 | } 47 | 48 | public override Task OnShowAsync(CancellationToken cancellationToken) 49 | { 50 | return base.OnShowAsync(cancellationToken); 51 | } 52 | 53 | public override Task OnHideAsync(CancellationToken cancellationToken) 54 | { 55 | // Auto save when closing? 56 | //content.ViewModel.SaveSettings(); 57 | return base.OnHideAsync(cancellationToken); 58 | } 59 | 60 | /// 61 | protected override void Dispose(bool disposing) 62 | { 63 | if (disposing) 64 | content.Dispose(); 65 | 66 | base.Dispose(disposing); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Commands/EFGitMigrationHookAddCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Commands; 2 | 3 | using BrightGit.Extensibility.Helpers; 4 | using BrightGit.SharpCommon; 5 | using Microsoft; 6 | using Microsoft.VisualStudio.Extensibility; 7 | using Microsoft.VisualStudio.Extensibility.Commands; 8 | using Microsoft.VisualStudio.Extensibility.Shell; 9 | using System.Diagnostics; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | 13 | [VisualStudioContribution] 14 | internal class EFGitMigrationHookAddCommand : Command 15 | { 16 | private readonly TraceSource logger; 17 | 18 | public EFGitMigrationHookAddCommand(TraceSource traceSource) 19 | { 20 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 21 | } 22 | 23 | /// 24 | public override CommandConfiguration CommandConfiguration => new(displayName: "EF Auto Migrator - Add Hook") 25 | { 26 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 27 | Icon = new(ImageMoniker.KnownValues.AddLink, IconSettings.IconAndText), 28 | }; 29 | 30 | /// 31 | public override Task InitializeAsync(CancellationToken cancellationToken) 32 | { 33 | // Use InitializeAsync for any one-time setup or initialization. 34 | return base.InitializeAsync(cancellationToken); 35 | } 36 | 37 | /// 38 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 39 | { 40 | try 41 | { 42 | var solutionDirectoryPath = await VSHelper.GetSolutionDirectoryAsync(Extensibility.Workspaces(), cancellationToken); 43 | if (string.IsNullOrWhiteSpace(solutionDirectoryPath)) 44 | { 45 | await Extensibility.Shell().ShowPromptAsync("Please open a solution before adding the hook.", PromptOptions.OK, cancellationToken); 46 | return; 47 | } 48 | 49 | SharpHookHelper.AddAutoMigratorHook(solutionDirectoryPath); 50 | await Extensibility.Shell().ShowPromptAsync($"Auto Migration hook added to repo {Path.GetDirectoryName(solutionDirectoryPath)}.", PromptOptions.OK, cancellationToken); 51 | } 52 | catch (Exception ex) 53 | { 54 | logger.TraceEvent(TraceEventType.Error, 0, ex.Message); 55 | await Extensibility.Shell().ShowPromptAsync(ex.Message, PromptOptions.OK, cancellationToken); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Commands/EFGitMigrationHookRemoveCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Commands; 2 | 3 | using BrightGit.Extensibility.Helpers; 4 | using BrightGit.SharpCommon; 5 | using Microsoft; 6 | using Microsoft.VisualStudio.Extensibility; 7 | using Microsoft.VisualStudio.Extensibility.Commands; 8 | using Microsoft.VisualStudio.Extensibility.Shell; 9 | using System.Diagnostics; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | 13 | [VisualStudioContribution] 14 | internal class EFGitMigrationHookRemoveCommand : Command 15 | { 16 | private readonly TraceSource logger; 17 | 18 | public EFGitMigrationHookRemoveCommand(TraceSource traceSource) 19 | { 20 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 21 | } 22 | 23 | /// 24 | public override CommandConfiguration CommandConfiguration => new(displayName: "EF Auto Migrator - Remove Hook") 25 | { 26 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 27 | Icon = new(ImageMoniker.KnownValues.RemoveLink, IconSettings.IconAndText), 28 | }; 29 | 30 | /// 31 | public override Task InitializeAsync(CancellationToken cancellationToken) 32 | { 33 | // Use InitializeAsync for any one-time setup or initialization. 34 | return base.InitializeAsync(cancellationToken); 35 | } 36 | 37 | /// 38 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 39 | { 40 | try 41 | { 42 | var solutionDirectoryPath = await VSHelper.GetSolutionDirectoryAsync(Extensibility.Workspaces(), cancellationToken); 43 | if (string.IsNullOrWhiteSpace(solutionDirectoryPath)) 44 | { 45 | await Extensibility.Shell().ShowPromptAsync("Please open a solution before removing the hook.", PromptOptions.OK, cancellationToken); 46 | return; 47 | } 48 | 49 | SharpHookHelper.RemoveAutoMigratorHook(solutionDirectoryPath); 50 | await Extensibility.Shell().ShowPromptAsync($"Auto Migration hook removed from {Path.GetDirectoryName(solutionDirectoryPath)}.", PromptOptions.OK, cancellationToken); 51 | } 52 | catch (Exception ex) 53 | { 54 | logger.TraceEvent(TraceEventType.Error, 0, ex.Message); 55 | await Extensibility.Shell().ShowPromptAsync(ex.Message, PromptOptions.OK, cancellationToken); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Services/TabsStorageService.cs: -------------------------------------------------------------------------------- 1 | using BrightGit.Extensibility.Models; 2 | using System.Diagnostics; 3 | using System.Text.Json; 4 | 5 | namespace BrightGit.Extensibility.Services; 6 | public class TabsStorageService 7 | { 8 | private const string fileName = "BrightTabs.json"; 9 | private readonly string fileDirectory; 10 | private readonly string filePath; 11 | 12 | public TabsStorageData Data { get; set; } = new(); 13 | 14 | public TabsStorageService() 15 | { 16 | fileDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "BrightExtensions"); 17 | filePath = Path.Combine(fileDirectory, fileName); 18 | Load(); 19 | } 20 | 21 | public void Load() 22 | { 23 | try 24 | { 25 | // Check if directory exists. 26 | if (!Directory.Exists(fileDirectory)) 27 | Directory.CreateDirectory(fileDirectory); 28 | 29 | // Load settings. 30 | if (File.Exists(filePath)) 31 | { 32 | var json = File.ReadAllText(filePath); 33 | Data = JsonSerializer.Deserialize(json) ?? new TabsStorageData(); 34 | } 35 | } 36 | catch (Exception ex) 37 | { 38 | Debug.WriteLine(ex); 39 | 40 | // Use default settings. 41 | Data = new TabsStorageData(); 42 | } 43 | } 44 | 45 | public void Save() 46 | { 47 | try 48 | { 49 | var json = JsonSerializer.Serialize(Data, new JsonSerializerOptions { WriteIndented = true }); 50 | File.WriteAllText(filePath, json); 51 | } 52 | catch (Exception ex) 53 | { 54 | // Add log? 55 | Debug.WriteLine(ex); 56 | } 57 | } 58 | 59 | public void AddTabsCustom(TabsInfo tabsInfo) 60 | { 61 | AddTabs(tabsInfo, Data.TabsCustom); 62 | } 63 | 64 | public void AddTabsBranch(TabsInfo tabsInfo) 65 | { 66 | AddTabs(tabsInfo, Data.TabsBranch); 67 | } 68 | 69 | private void AddTabs(TabsInfo tabsInfo, List tabs) 70 | { 71 | if (tabsInfo != null) 72 | { 73 | // Remove existing tabs info if any. 74 | var existingTabsInfo = tabs.FirstOrDefault(x => x.Id == tabsInfo.Id); 75 | if (existingTabsInfo != null) 76 | tabs.Remove(existingTabsInfo); 77 | 78 | // Add new tabs info. 79 | tabs.Add(tabsInfo); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Commands/EFGitMigrationHookCheckCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Commands; 2 | 3 | using BrightGit.Extensibility.Helpers; 4 | using BrightGit.SharpCommon; 5 | using Microsoft; 6 | using Microsoft.VisualStudio.Extensibility; 7 | using Microsoft.VisualStudio.Extensibility.Commands; 8 | using Microsoft.VisualStudio.Extensibility.Shell; 9 | using System.Diagnostics; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | 13 | [VisualStudioContribution] 14 | internal class EFGitMigrationHookCheckCommand : Command 15 | { 16 | private readonly TraceSource logger; 17 | 18 | public EFGitMigrationHookCheckCommand(TraceSource traceSource) 19 | { 20 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 21 | } 22 | 23 | /// 24 | public override CommandConfiguration CommandConfiguration => new(displayName: "EF Auto Migrator - Check Hook State") 25 | { 26 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 27 | Icon = new(ImageMoniker.KnownValues.LinkAlert, IconSettings.IconAndText), 28 | }; 29 | 30 | /// 31 | public override Task InitializeAsync(CancellationToken cancellationToken) 32 | { 33 | // Use InitializeAsync for any one-time setup or initialization. 34 | return base.InitializeAsync(cancellationToken); 35 | } 36 | 37 | /// 38 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 39 | { 40 | try 41 | { 42 | var solutionDirectoryPath = await VSHelper.GetSolutionDirectoryAsync(Extensibility.Workspaces(), cancellationToken); 43 | if (string.IsNullOrWhiteSpace(solutionDirectoryPath)) 44 | { 45 | await Extensibility.Shell().ShowPromptAsync("Please open a solution before checking the hook state.", PromptOptions.OK, cancellationToken); 46 | return; 47 | } 48 | 49 | var isHookActive = SharpHookHelper.CheckAutoMigratorHook(solutionDirectoryPath); 50 | var msg = isHookActive ? "Auto Migration hook is active for this repo." : "Auto Migration hook is NOT active for this repo."; 51 | await Extensibility.Shell().ShowPromptAsync(msg, PromptOptions.OK, cancellationToken); 52 | } 53 | catch (Exception ex) 54 | { 55 | logger.TraceEvent(TraceEventType.Error, 0, ex.Message); 56 | await Extensibility.Shell().ShowPromptAsync(ex.Message, PromptOptions.OK, cancellationToken); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/HelpWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility.Windows; 2 | 3 | using BrightXaml.Extensibility.Models; 4 | using Microsoft.VisualStudio.Extensibility.UI; 5 | using System.Collections.ObjectModel; 6 | using System.Runtime.Serialization; 7 | 8 | [DataContract] 9 | internal class HelpWindowViewModel : NotifyPropertyChangedObject 10 | { 11 | [DataMember] 12 | public string Text { get => _text; set => SetProperty(ref _text, value); } 13 | private string _text = string.Empty; 14 | 15 | [DataMember] 16 | public ObservableCollection CommandsInfo { get => _commandsInfo; set => SetProperty(ref _commandsInfo, value); } 17 | private ObservableCollection _commandsInfo; 18 | 19 | [DataMember] 20 | public AsyncCommand RefreshCommand { get; } 21 | 22 | public HelpWindowViewModel() 23 | { 24 | RefreshCommand = new AsyncCommand((parameter, clientContext, cancellationToken) => 25 | { 26 | InitializeCommandsInfo(); 27 | return Task.CompletedTask; 28 | }); 29 | RefreshCommand.CanExecute = Meta.IsDebug; 30 | 31 | InitializeCommandsInfo(); 32 | } 33 | 34 | private void InitializeCommandsInfo() 35 | { 36 | CommandsInfo = new ObservableCollection 37 | { 38 | new() { Name = "Clean Solution Bin and Obj", Description = "Clean 'bin' and 'obj' folders from all projects in the solution" }, 39 | new() { Name = "Kill XAML Designer Process", Description = "Kills the WpfSurface.exe process, VS can auto reload it later" }, 40 | //new() { Name = "Extract Classes Being Used", Description = "Copy to the clipboard all C# classes being referenced by the current class" }, 41 | //new() { Name = "Extract Directory", Description = "Copy to the clipboard all coding files from the current directory" }, 42 | new() { Name = "Format Xaml", Description = "Format the current XAML file (preserves tags position and indentation)" }, 43 | new() { Name = "Property To INPC", Description = "Convert regular properties to INotifyPropertyChanged properties" }, 44 | new() { Name = "Automatically Go To Binding Definition", Description = "When pressing F12, if a SourceGenerator file is opened by VS,\nautomatically open the actual command in the ViewModel" }, 45 | new() { Name = "Show View/ViewModel", Description = "Display the view of the current ViewModel and vice-versa" }, 46 | //new() { Name = "Show View", Description = "Display the view of the current ViewModel" }, 47 | //new() { Name = "Show View Model", Description = "Display the ViewModel of the current View (.xaml | .xaml.cs)" } 48 | }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Helpers/ClipboardHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Windows; 3 | 4 | namespace BrightXaml.Extensibility.Helpers; 5 | public static class ClipboardHelper 6 | { 7 | /// 8 | /// Most reliable and fastest way to copy text to clipboard. 9 | /// 10 | public static void SetClipboard(string text) 11 | { 12 | if (text == null) 13 | throw new ArgumentNullException("Attempt to set clipboard with null"); 14 | 15 | var clipboardExecutable = new Process(); 16 | clipboardExecutable.StartInfo = new ProcessStartInfo 17 | { 18 | RedirectStandardInput = true, 19 | FileName = @"clip", 20 | UseShellExecute = false, 21 | CreateNoWindow = true, 22 | }; 23 | clipboardExecutable.Start(); 24 | 25 | // CLIP uses STDIN as input. 26 | clipboardExecutable.StandardInput.Write(text); 27 | 28 | // When we are done writing all the string, close it so clip doesn't wait and get stuck. 29 | clipboardExecutable.StandardInput.Close(); 30 | 31 | return; 32 | } 33 | 34 | /// 35 | /// Really slow and unreliable. 36 | /// 37 | public static void SetTextClipboard(string text) 38 | { 39 | if (!string.IsNullOrWhiteSpace(text)) 40 | { 41 | var thread = new Thread(() => 42 | { 43 | int retryCount = 10; 44 | bool success = false; 45 | 46 | while (!success && retryCount-- > 0) 47 | { 48 | try 49 | { 50 | Clipboard.SetText(text); 51 | success = true; 52 | } 53 | catch (System.Runtime.InteropServices.COMException) 54 | { 55 | // Wait and retry. 56 | Thread.Sleep(100); 57 | } 58 | } 59 | 60 | if (!success) 61 | { 62 | Debug.WriteLine("Failed to copy text to clipboard. Please try again."); 63 | } 64 | }); 65 | 66 | thread.SetApartmentState(ApartmentState.STA); 67 | thread.Start(); 68 | thread.Join(); 69 | } 70 | } 71 | 72 | /// 73 | /// [WIP] It works cross-platform. 74 | /// Add: 75 | /// using Windows.ApplicationModel.DataTransfer; 76 | /// 77 | public static void SetContentClipboardPackage(string text) 78 | { 79 | //DataPackage package = new DataPackage(); 80 | //package.SetText("text to copy"); 81 | //Clipboard.SetContent(package); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /BrightGit.SharpAutoMigrator/DotnetHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace EFCoreGitAutoMigration; 4 | public static class DotnetHelper 5 | { 6 | public static Task UpdateDatabaseEFCoreAsync(string projectDir, string migrationName) 7 | { 8 | return RunDotnetCommandAsync(projectDir, $"ef database update {migrationName}"); 9 | } 10 | 11 | public static async Task RunDotnetCommandAsync(string projectDir, string arguments) 12 | { 13 | ProcessStartInfo startInfo = new ProcessStartInfo 14 | { 15 | FileName = "dotnet", 16 | Arguments = arguments, 17 | RedirectStandardOutput = true, 18 | RedirectStandardError = true, 19 | UseShellExecute = false, 20 | CreateNoWindow = true, 21 | WorkingDirectory = projectDir 22 | }; 23 | 24 | using (Process process = new Process { StartInfo = startInfo }) 25 | { 26 | process.OutputDataReceived += (sender, e) => Console.WriteLine(e.Data); 27 | process.ErrorDataReceived += (sender, e) => Console.WriteLine(e.Data); 28 | 29 | process.Start(); 30 | process.BeginOutputReadLine(); 31 | process.BeginErrorReadLine(); 32 | await process.WaitForExitAsync(); 33 | 34 | return process.ExitCode == 0; 35 | } 36 | } 37 | 38 | public static async Task CheckDotnetToolInstalledAsync(string toolName) 39 | { 40 | var startInfo = new ProcessStartInfo 41 | { 42 | FileName = "dotnet", 43 | Arguments = "tool list --global", 44 | RedirectStandardOutput = true, 45 | UseShellExecute = false, 46 | CreateNoWindow = true 47 | }; 48 | 49 | using (Process process = new Process { StartInfo = startInfo }) 50 | { 51 | process.Start(); 52 | string output = process.StandardOutput.ReadToEnd(); 53 | await process.WaitForExitAsync(); 54 | 55 | // Check if the toolName is in the output 56 | return output.Contains(toolName, StringComparison.OrdinalIgnoreCase); 57 | } 58 | } 59 | 60 | public static Task CheckDotnetT4Installed() 61 | { 62 | return CheckDotnetToolInstalledAsync("dotnet-t4"); 63 | } 64 | 65 | public static Task CheckDotnetEFInstalled() 66 | { 67 | return CheckDotnetToolInstalledAsync("dotnet-ef"); 68 | } 69 | 70 | public static void BuildSolutionEFCore(string solutionPath) 71 | { 72 | var startInfo = new ProcessStartInfo 73 | { 74 | FileName = "dotnet", 75 | Arguments = "build", 76 | RedirectStandardOutput = true, 77 | UseShellExecute = false, 78 | CreateNoWindow = true, 79 | }; 80 | 81 | using (Process process = new Process { StartInfo = startInfo }) 82 | { 83 | process.Start(); 84 | process.WaitForExit(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /BrightGit.SharpCommon/DotnetHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace BrightGit.SharpCommon; 4 | public static class DotnetHelper 5 | { 6 | public static Task UpdateDatabaseEFCoreAsync(string projectDir, string migrationName) 7 | { 8 | return RunDotnetCommandAsync(projectDir, $"ef database update {migrationName}"); 9 | } 10 | 11 | public static async Task RunDotnetCommandAsync(string projectDir, string arguments) 12 | { 13 | ProcessStartInfo startInfo = new ProcessStartInfo 14 | { 15 | FileName = "dotnet", 16 | Arguments = arguments, 17 | RedirectStandardOutput = true, 18 | RedirectStandardError = true, 19 | UseShellExecute = false, 20 | CreateNoWindow = true, 21 | WorkingDirectory = projectDir 22 | }; 23 | 24 | using (Process process = new Process { StartInfo = startInfo }) 25 | { 26 | process.OutputDataReceived += (sender, e) => { Console.WriteLine(e.Data); Debug.WriteLine(e.Data); }; 27 | process.ErrorDataReceived += (sender, e) => { Console.WriteLine(e.Data); Debug.WriteLine(e.Data); }; 28 | 29 | process.Start(); 30 | process.BeginOutputReadLine(); 31 | process.BeginErrorReadLine(); 32 | await process.WaitForExitAsync(); 33 | 34 | return process.ExitCode == 0; 35 | } 36 | } 37 | 38 | public static async Task CheckDotnetToolInstalledAsync(string toolName) 39 | { 40 | var startInfo = new ProcessStartInfo 41 | { 42 | FileName = "dotnet", 43 | Arguments = "tool list --global", 44 | RedirectStandardOutput = true, 45 | UseShellExecute = false, 46 | CreateNoWindow = true 47 | }; 48 | 49 | using (Process process = new Process { StartInfo = startInfo }) 50 | { 51 | process.Start(); 52 | string output = process.StandardOutput.ReadToEnd(); 53 | await process.WaitForExitAsync(); 54 | 55 | // Check if the toolName is in the output 56 | return output.Contains(toolName, StringComparison.OrdinalIgnoreCase); 57 | } 58 | } 59 | 60 | public static Task CheckDotnetT4Installed() 61 | { 62 | return CheckDotnetToolInstalledAsync("dotnet-t4"); 63 | } 64 | 65 | public static Task CheckDotnetEFInstalled() 66 | { 67 | return CheckDotnetToolInstalledAsync("dotnet-ef"); 68 | } 69 | 70 | public static void BuildSolutionEFCore(string solutionPath) 71 | { 72 | var startInfo = new ProcessStartInfo 73 | { 74 | FileName = "dotnet", 75 | Arguments = "build", 76 | RedirectStandardOutput = true, 77 | UseShellExecute = false, 78 | CreateNoWindow = true, 79 | }; 80 | 81 | using (Process process = new Process { StartInfo = startInfo }) 82 | { 83 | process.Start(); 84 | process.WaitForExit(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/ExtensionEntrypoint.cs: -------------------------------------------------------------------------------- 1 | namespace BrightXaml.Extensibility; 2 | 3 | using BrightXaml.Extensibility.Commands; 4 | using BrightXaml.Extensibility.Services; 5 | using BrightXaml.Extensibility.Windows; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.VisualStudio.Extensibility; 8 | using Microsoft.VisualStudio.Extensibility.Commands; 9 | 10 | /// 11 | /// Extension entrypoint for the VisualStudio.Extensibility extension. 12 | /// 13 | [VisualStudioContribution] 14 | internal class ExtensionEntrypoint : Extension 15 | { 16 | /// 17 | public override ExtensionConfiguration ExtensionConfiguration => new() 18 | { 19 | Metadata = new( 20 | id: "BrightXaml.c6b5c335-85e8-4243-bdf1-2b6468178ad1", 21 | version: this.ExtensionAssemblyVersion, 22 | publisherName: "Luis Henrique Goll", 23 | displayName: "Bright Xaml Extension", 24 | description: "Bright Commands and Automations made with Xaml Developers in mind! (WPF, MAUI, WinUI)"), 25 | }; 26 | 27 | [VisualStudioContribution] 28 | //public static MenuConfiguration MyMenu => new("%MyMenu.DisplayName%") 29 | public static MenuConfiguration MyMenu => new("Bright Xaml") 30 | { 31 | Placements = new CommandPlacement[] 32 | { 33 | CommandPlacement.KnownPlacements.ExtensionsMenu 34 | }, 35 | Children = new[] 36 | { 37 | MenuChild.Command(), 38 | //MenuChild.Command(), 39 | //MenuChild.Command(), 40 | //MenuChild.Command(), 41 | MenuChild.Separator, 42 | MenuChild.Command(), 43 | MenuChild.Command(), 44 | MenuChild.Separator, 45 | MenuChild.Command(), 46 | MenuChild.Command(), 47 | //MenuChild.Separator, 48 | MenuChild.Command(), 49 | #if DEBUG 50 | MenuChild.Command(), 51 | MenuChild.Separator, 52 | MenuChild.Command(), 53 | MenuChild.Separator, 54 | MenuChild.Command(), 55 | MenuChild.Command(), 56 | #endif 57 | MenuChild.Separator, 58 | MenuChild.Command(), 59 | MenuChild.Command(), 60 | }, 61 | }; 62 | 63 | /// 64 | protected override void InitializeServices(IServiceCollection serviceCollection) 65 | { 66 | base.InitializeServices(serviceCollection); 67 | 68 | // You can configure dependency injection here by adding services to the serviceCollection. 69 | serviceCollection.AddTransient(provider => new DialogService()); 70 | serviceCollection.AddSingleton(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /BrightGit.Extensibility/Commands/TabsSortCommand.cs: -------------------------------------------------------------------------------- 1 | namespace BrightGit.Extensibility.Commands; 2 | 3 | using Microsoft; 4 | using Microsoft.VisualStudio.Extensibility; 5 | using Microsoft.VisualStudio.Extensibility.Commands; 6 | using Microsoft.VisualStudio.Extensibility.Shell; 7 | using Microsoft.VisualStudio.RpcContracts.Documents; 8 | using System.Diagnostics; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | [VisualStudioContribution] 13 | internal class TabsSortCommand : Command 14 | { 15 | private readonly TraceSource logger; 16 | 17 | public TabsSortCommand(TraceSource traceSource) 18 | { 19 | this.logger = Requires.NotNull(traceSource, nameof(traceSource)); 20 | } 21 | 22 | /// 23 | public override CommandConfiguration CommandConfiguration => new(displayName: "(WIP) Sort Tabs") 24 | { 25 | //Placements = [CommandPlacement.KnownPlacements.ExtensionsMenu], 26 | Icon = new(ImageMoniker.KnownValues.SaveFileDialog, IconSettings.IconAndText), 27 | }; 28 | 29 | /// 30 | public override Task InitializeAsync(CancellationToken cancellationToken) 31 | { 32 | // Use InitializeAsync for any one-time setup or initialization. 33 | return base.InitializeAsync(cancellationToken); 34 | } 35 | 36 | /// 37 | public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken) 38 | { 39 | try 40 | { 41 | var sw = Stopwatch.StartNew(); 42 | 43 | var openedDocuments = await Extensibility.Documents().GetOpenDocumentsAsync(cancellationToken); 44 | if (openedDocuments.Any()) 45 | { 46 | var sortedDocuments = openedDocuments.OrderBy(d => Path.GetFileName(d.Moniker.LocalPath)).ToList(); 47 | 48 | // TODO: This is a terrible way to do this... I couldn't find a better way to simply reorder the tabs with the API. 49 | 50 | // Close all documents. 51 | //await Task.WhenAll(openedDocuments.Select(document => document.CloseAsync(SaveDocumentOption.PromptSave, Extensibility, cancellationToken))); 52 | await Task.WhenAll(openedDocuments.Select(document => Extensibility.Documents().CloseDocumentAsync(document.Moniker, SaveDocumentOption.PromptSave, cancellationToken))); 53 | 54 | // Open documents in sorted order. 55 | await Task.WhenAll(sortedDocuments.Select(document => Extensibility.Documents().OpenDocumentAsync(document.Moniker, cancellationToken))); 56 | 57 | sw.Stop(); 58 | Debug.WriteLine($"Sorted {openedDocuments.Count} tabs in {sw.ElapsedMilliseconds}ms"); 59 | await Extensibility.Shell().ShowPromptAsync($"Sorted {openedDocuments.Count} tabs in {sw.ElapsedMilliseconds}ms", PromptOptions.OK, cancellationToken); 60 | } 61 | else 62 | { 63 | await Extensibility.Shell().ShowPromptAsync("No tabs to sort", PromptOptions.OK, cancellationToken); 64 | return; 65 | } 66 | } 67 | catch (Exception ex) 68 | { 69 | Debug.WriteLine(ex); 70 | await Extensibility.Shell().ShowPromptAsync("An error occurred while sorting tabs", PromptOptions.OK, cancellationToken); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /BrightXaml.Extensibility/Windows/HelpWindowContent.xaml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 16 | 14 | 18 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |