diff --git a/bin/pyrevit.exe b/bin/pyrevit.exe old mode 100644 new mode 100755 diff --git a/dev/pyRevitLabs/pyRevitCLI/PyRevitCLIAppHelps.cs b/dev/pyRevitLabs/pyRevitCLI/PyRevitCLIAppHelps.cs index acb679e3bf..c5e48a6b31 100644 --- a/dev/pyRevitLabs/pyRevitCLI/PyRevitCLIAppHelps.cs +++ b/dev/pyRevitLabs/pyRevitCLI/PyRevitCLIAppHelps.cs @@ -376,88 +376,77 @@ private static void BuildHelp(IEnumerable docoptKeywords, IDictionary mgmtCommands = null, IDictionary commands = null, IDictionary helpCommands = null, - IDictionary options = null) { + IDictionary options = null) + { // print commands help - int indent = 25; - string outputFormat = " {0,-" + indent.ToString() + "}{1}"; + const int indent = 25; - var helpString = ""; // header - helpString += header + Environment.NewLine; - helpString += Environment.NewLine; + PyRevitCLIColorfulConsole.WriteLine(header); + PyRevitCLIColorfulConsole.WriteLine(string.Empty); // build a help guide for a subcommand based on doctop usage entries - if (docoptKeywords != null) { + if (docoptKeywords != null) + { foreach (var hline in PyRevitCLI.UsagePatterns.GetLines()) if (hline.Contains("Usage:")) - helpString += hline + Environment.NewLine; + PyRevitCLIColorfulConsole.WriteUsage(hline); else - foreach (var kword in docoptKeywords) { + foreach (var kword in docoptKeywords) + { if ((hline.Contains("pyrevit " + kword + " ") || hline.EndsWith(" " + kword)) && !hline.Contains("pyrevit " + kword + " --help")) - helpString += " " + hline.Trim() + Environment.NewLine; + PyRevitCLIColorfulConsole.WriteLine(" " + hline.Trim()); } - helpString += Environment.NewLine; + PyRevitCLIColorfulConsole.WriteLine(string.Empty); } if (optionsfirst) - helpString = BuildOptions( - helpString, + PrintOptions( header: " Options:", options: options, - outputFormat: outputFormat + indent: indent ); - helpString = BuildOptions( - helpString, + PrintOptions( header: " Management Commands:", options: mgmtCommands, - outputFormat: outputFormat + indent: indent ); - helpString = BuildOptions( - helpString, + PrintOptions( header: " Commands:", options: commands, - outputFormat: outputFormat + indent: indent ); - helpString = BuildOptions( - helpString, + PrintOptions( header: " Help Commands:", options: helpCommands, - outputFormat: outputFormat + indent: indent ); if (!optionsfirst) - helpString = BuildOptions( - helpString, + PrintOptions( header: " Arguments & Options:", options: options, - outputFormat: outputFormat + indent: indent ); // footer if (footer != null) - helpString += footer + Environment.NewLine; - - Console.WriteLine(helpString); + PyRevitCLIColorfulConsole.WriteLine(footer); } - private static string BuildOptions(string baseHelp, string header, IDictionary options, string outputFormat) { - if (options != null) { - baseHelp += header + Environment.NewLine; - foreach (var optionPair in options) { - baseHelp += - string.Format(outputFormat, optionPair.Key, optionPair.Value) - + Environment.NewLine; - } - baseHelp += Environment.NewLine; - - return baseHelp; + private static void PrintOptions(string header, IDictionary options, int indent) + { + if (options != null) + { + PyRevitCLIColorfulConsole.WriteHeader(header); + foreach (var optionPair in options) + PyRevitCLIColorfulConsole.WriteCommand(optionPair.Key, optionPair.Value, indent); + PyRevitCLIColorfulConsole.WriteLine(string.Empty); } - - return baseHelp; } } } diff --git a/dev/pyRevitLabs/pyRevitCLI/PyRevitCLIColorfulConsole.cs b/dev/pyRevitLabs/pyRevitCLI/PyRevitCLIColorfulConsole.cs new file mode 100644 index 0000000000..32ec16921f --- /dev/null +++ b/dev/pyRevitLabs/pyRevitCLI/PyRevitCLIColorfulConsole.cs @@ -0,0 +1,38 @@ +using System.Drawing; + +using Console = Colorful.Console; + + +namespace pyRevitCLI +{ + internal static class PyRevitCLIColorfulConsole + { + private static readonly Color CommandColor = Color.Yellow; + private static readonly Color HeaderColor = Color.Cyan; + private static readonly Color AccentColor = Color.FromArgb(126, 226, 110); + + internal static void WriteLine(string text) + { + Console.WriteLine(text); + } + + internal static void WriteHeader(string text) + { + Console.WriteLine(text, HeaderColor); + } + + internal static void WriteCommand(string command, string description, int indent) + { + string outputFormat = " {0,-" + indent.ToString() + "}"; + Console.Write(string.Format(outputFormat, command), CommandColor); + Console.WriteLine(description); + } + + internal static void WriteUsage(string line) + { + var lineParts = line.Split(new char[] { ' ' }, 2); + Console.Write(lineParts[0] + " ", AccentColor); + Console.WriteLine(lineParts[1]); + } + } +} diff --git a/dev/pyRevitLabs/pyRevitLabs.Emojis/Emojis.cs b/dev/pyRevitLabs/pyRevitLabs.Emojis/Emojis.cs index 9234b4efc3..b61164d7ce 100644 --- a/dev/pyRevitLabs/pyRevitLabs.Emojis/Emojis.cs +++ b/dev/pyRevitLabs/pyRevitLabs.Emojis/Emojis.cs @@ -1900,7 +1900,6 @@ public static class Emojis { { "princess_medium-light_skin_tone", "1F478-1F3FC" }, { "princess_medium_skin_tone", "1F478-1F3FD" }, { "printer", "1F5A8" }, - { "prohibited", "1F6AB" }, { "purple_heart", "1F49C" }, { "purse", "1F45B" }, { "pushpin", "1F4CC" }, diff --git a/dev/pyRevitLabs/pyRevitLabs.UnitTests/PyRevitCLITests.cs b/dev/pyRevitLabs/pyRevitLabs.UnitTests/PyRevitCLITests.cs new file mode 100644 index 0000000000..4cd3ffcee8 --- /dev/null +++ b/dev/pyRevitLabs/pyRevitLabs.UnitTests/PyRevitCLITests.cs @@ -0,0 +1,44 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.IO; +using pyRevitCLI; + +namespace pyRevitLabs.UnitTests +{ + [TestClass] + public class PyRevitCLITests + { + [TestMethod] + public void TestHelpMessageColors() + { + // Redirect console output to a StringWriter + var stringWriter = new StringWriter(); + var originalOutput = Console.Out; + Console.SetOut(stringWriter); + + try + { + // Call the method that prints the help message + PyRevitCLIAppHelps.PrintHelp(PyRevitCLICommandType.Main, 0); + } + catch (Exception) + { + // The PrintHelp method calls Environment.Exit, which throws an exception in the test runner. + // We can ignore this exception as we are only interested in the console output. + } + finally + { + // Restore the original console output + Console.SetOut(originalOutput); + } + + // Get the output + var output = stringWriter.ToString(); + + // Assert that the output contains color codes + // This is a simple check to ensure that Colorful.Console is being used. + // A more robust test would check for specific colors on specific parts of the text. + Assert.IsTrue(output.Contains("\u001b[")); + } + } +} diff --git a/dev/pyRevitLabs/pyRevitLabs.UnitTests/pyRevitLabs.UnitTests.csproj b/dev/pyRevitLabs/pyRevitLabs.UnitTests/pyRevitLabs.UnitTests.csproj index b6275ef2c7..4b654844fe 100644 --- a/dev/pyRevitLabs/pyRevitLabs.UnitTests/pyRevitLabs.UnitTests.csproj +++ b/dev/pyRevitLabs/pyRevitLabs.UnitTests/pyRevitLabs.UnitTests.csproj @@ -19,5 +19,6 @@ + diff --git a/release/pyrevit-admin.iss b/release/pyrevit-admin.iss index 229b06d67f..ba0c00f83f 100644 --- a/release/pyrevit-admin.iss +++ b/release/pyrevit-admin.iss @@ -85,3 +85,85 @@ Filename: "{app}\bin\pyrevit.exe"; Description: "Attaching this clone..."; Param [UninstallRun] Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "ClearCaches"; Parameters: "caches clear --all"; Flags: runhidden runascurrentuser Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "DetachClones"; Parameters: "detach --all"; Flags: runhidden runascurrentuser + +[Code] +const + REQUIRED_MAJOR_VERSION = 8; + +function CheckForDotNetRuntime(Path: String; var FoundVersion: String): Boolean; +var + FindRec: TFindRec; + Version: String; + Major: Integer; + SeparatorPos: Integer; +begin + Result := False; + if DirExists(Path) then + begin + if FindFirst(Path + '\*', FindRec) then + begin + try + repeat + if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and (FindRec.Name <> '.') and (FindRec.Name <> '..') then + begin + Version := FindRec.Name; + SeparatorPos := Pos('.', Version); + if SeparatorPos > 0 then + begin + try + Major := StrToInt(Copy(Version, 1, SeparatorPos - 1)); + if Major >= REQUIRED_MAJOR_VERSION then + begin + FoundVersion := Version; + Result := True; + Exit; + end; + except + end; + end; + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; + end; +end; + +procedure GetDotNetDesktopRuntimeInfo(var Found: Boolean; var Version: String; var Path: String); +var + PathX64, PathX86: String; +begin + PathX64 := ExpandConstant('{pf64}\dotnet\shared\Microsoft.WindowsDesktop.App'); + PathX86 := ExpandConstant('{pf32}\dotnet\shared\Microsoft.WindowsDesktop.App'); + + Found := CheckForDotNetRuntime(PathX64, Version); + if Found then + begin + Path := PathX64; + Exit; + end; + + Found := CheckForDotNetRuntime(PathX86, Version); + if Found then + begin + Path := PathX86; + Exit; + end; +end; + +procedure InitializeWizard(); +var + IsInstalled: Boolean; + FoundVersion, FoundPath: String; +begin + GetDotNetDesktopRuntimeInfo(IsInstalled, FoundVersion, FoundPath); + if IsInstalled then + begin + MsgBox('Found compatible .NET Desktop Runtime.'#13#10#13#10'Version: ' + FoundVersion + #13#10'Path: ' + FoundPath, mbInformation, MB_OK); + end + else + begin + MsgBox('Could not find .NET 8 Desktop Runtime.', mbError, MB_OK); + end; +end; diff --git a/release/pyrevit-cli-admin.iss b/release/pyrevit-cli-admin.iss index df6ac2f564..f5390cec4e 100644 --- a/release/pyrevit-cli-admin.iss +++ b/release/pyrevit-cli-admin.iss @@ -60,4 +60,87 @@ Filename: "{app}\bin\pyrevit.exe"; Description: "Detach existing clones..."; Par [UninstallRun] Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "ClearCaches"; Parameters: "caches clear --all"; Flags: runhidden runascurrentuser -Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "DetachClones"; Parameters: "detach --all"; Flags: runhidden runascurrentuser \ No newline at end of file +Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "DetachClones"; Parameters: "detach --all"; Flags: runhidden runascurrentuser + +[Code] +const + REQUIRED_MAJOR_VERSION = 8; + +function CheckForDotNetRuntime(Path: String; var FoundVersion: String): Boolean; +var + FindRec: TFindRec; + Version: String; + Major: Integer; + SeparatorPos: Integer; +begin + Result := False; + if DirExists(Path) then + begin + if FindFirst(Path + '\*', FindRec) then + begin + try + repeat + if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and (FindRec.Name <> '.') and (FindRec.Name <> '..') then + begin + Version := FindRec.Name; + SeparatorPos := Pos('.', Version); + if SeparatorPos > 0 then + begin + try + Major := StrToInt(Copy(Version, 1, SeparatorPos - 1)); + if Major >= REQUIRED_MAJOR_VERSION then + begin + FoundVersion := Version; + Result := True; + Exit; + end; + except + end; + end; + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; + end; +end; + +procedure GetDotNetDesktopRuntimeInfo(var Found: Boolean; var Version: String; var Path: String); +var + PathX64, PathX86: String; +begin + PathX64 := ExpandConstant('{pf64}\dotnet\shared\Microsoft.WindowsDesktop.App'); + PathX86 := ExpandConstant('{pf32}\dotnet\shared\Microsoft.WindowsDesktop.App'); + + Found := CheckForDotNetRuntime(PathX64, Version); + if Found then + begin + Path := PathX64; + Exit; + end; + + Found := CheckForDotNetRuntime(PathX86, Version); + if Found then + begin + Path := PathX86; + Exit; + end; +end; + +procedure InitializeWizard(); +var + IsInstalled: Boolean; + FoundVersion, FoundPath: String; +begin + GetDotNetDesktopRuntimeInfo(IsInstalled, FoundVersion, FoundPath); + if IsInstalled then + begin + MsgBox('Found compatible .NET Desktop Runtime.'#13#10#13#10'Version: ' + FoundVersion + #13#10'Path: ' + FoundPath, mbInformation, MB_OK); + end + else + begin + MsgBox('Could not find .NET 8 Desktop Runtime.', mbError, MB_OK); + end; +end; + diff --git a/release/pyrevit-cli.iss b/release/pyrevit-cli.iss index cdbddaeaaa..c7ab99c841 100644 --- a/release/pyrevit-cli.iss +++ b/release/pyrevit-cli.iss @@ -60,4 +60,87 @@ Filename: "{app}\bin\pyrevit.exe"; Description: "Detach existing clones..."; Par [UninstallRun] Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "ClearCaches"; Parameters: "caches clear --all"; Flags: runhidden -Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "DetachClones"; Parameters: "detach --all"; Flags: runhidden \ No newline at end of file +Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "DetachClones"; Parameters: "detach --all"; Flags: runhidden + +[Code] +const + REQUIRED_MAJOR_VERSION = 8; + +function CheckForDotNetRuntime(Path: String; var FoundVersion: String): Boolean; +var + FindRec: TFindRec; + Version: String; + Major: Integer; + SeparatorPos: Integer; +begin + Result := False; + if DirExists(Path) then + begin + if FindFirst(Path + '\*', FindRec) then + begin + try + repeat + if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and (FindRec.Name <> '.') and (FindRec.Name <> '..') then + begin + Version := FindRec.Name; + SeparatorPos := Pos('.', Version); + if SeparatorPos > 0 then + begin + try + Major := StrToInt(Copy(Version, 1, SeparatorPos - 1)); + if Major >= REQUIRED_MAJOR_VERSION then + begin + FoundVersion := Version; + Result := True; + Exit; + end; + except + end; + end; + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; + end; +end; + +procedure GetDotNetDesktopRuntimeInfo(var Found: Boolean; var Version: String; var Path: String); +var + PathX64, PathX86: String; +begin + PathX64 := ExpandConstant('{pf64}\dotnet\shared\Microsoft.WindowsDesktop.App'); + PathX86 := ExpandConstant('{pf32}\dotnet\shared\Microsoft.WindowsDesktop.App'); + + Found := CheckForDotNetRuntime(PathX64, Version); + if Found then + begin + Path := PathX64; + Exit; + end; + + Found := CheckForDotNetRuntime(PathX86, Version); + if Found then + begin + Path := PathX86; + Exit; + end; +end; + +procedure InitializeWizard(); +var + IsInstalled: Boolean; + FoundVersion, FoundPath: String; +begin + GetDotNetDesktopRuntimeInfo(IsInstalled, FoundVersion, FoundPath); + if IsInstalled then + begin + MsgBox('Found compatible .NET Desktop Runtime.'#13#10#13#10'Version: ' + FoundVersion + #13#10'Path: ' + FoundPath, mbInformation, MB_OK); + end + else + begin + MsgBox('Could not find .NET 8 Desktop Runtime.', mbError, MB_OK); + end; +end; + diff --git a/release/pyrevit.iss b/release/pyrevit.iss index 1048dfa6f8..ae3f814ef6 100644 --- a/release/pyrevit.iss +++ b/release/pyrevit.iss @@ -85,3 +85,85 @@ Filename: "{app}\bin\pyrevit.exe"; Description: "Attaching this clone..."; Param [UninstallRun] Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "ClearCaches"; Parameters: "caches clear --all"; Flags: runhidden Filename: "{app}\bin\pyrevit.exe"; RunOnceId: "DetachClones"; Parameters: "detach --all"; Flags: runhidden + +[Code] +const + REQUIRED_MAJOR_VERSION = 8; + +function CheckForDotNetRuntime(Path: String; var FoundVersion: String): Boolean; +var + FindRec: TFindRec; + Version: String; + Major: Integer; + SeparatorPos: Integer; +begin + Result := False; + if DirExists(Path) then + begin + if FindFirst(Path + '\*', FindRec) then + begin + try + repeat + if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and (FindRec.Name <> '.') and (FindRec.Name <> '..') then + begin + Version := FindRec.Name; + SeparatorPos := Pos('.', Version); + if SeparatorPos > 0 then + begin + try + Major := StrToInt(Copy(Version, 1, SeparatorPos - 1)); + if Major >= REQUIRED_MAJOR_VERSION then + begin + FoundVersion := Version; + Result := True; + Exit; + end; + except + end; + end; + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; + end; +end; + +procedure GetDotNetDesktopRuntimeInfo(var Found: Boolean; var Version: String; var Path: String); +var + PathX64, PathX86: String; +begin + PathX64 := ExpandConstant('{pf64}\dotnet\shared\Microsoft.WindowsDesktop.App'); + PathX86 := ExpandConstant('{pf32}\dotnet\shared\Microsoft.WindowsDesktop.App'); + + Found := CheckForDotNetRuntime(PathX64, Version); + if Found then + begin + Path := PathX64; + Exit; + end; + + Found := CheckForDotNetRuntime(PathX86, Version); + if Found then + begin + Path := PathX86; + Exit; + end; +end; + +procedure InitializeWizard(); +var + IsInstalled: Boolean; + FoundVersion, FoundPath: String; +begin + GetDotNetDesktopRuntimeInfo(IsInstalled, FoundVersion, FoundPath); + if IsInstalled then + begin + MsgBox('Found compatible .NET Desktop Runtime.'#13#10#13#10'Version: ' + FoundVersion + #13#10'Path: ' + FoundPath, mbInformation, MB_OK); + end + else + begin + MsgBox('Could not find .NET 8 Desktop Runtime.', mbError, MB_OK); + end; +end;