From fdd58a296a7a50f8d368bdbb9d1730119521686d Mon Sep 17 00:00:00 2001 From: Kingcean Date: Wed, 6 Dec 2023 14:49:13 +0800 Subject: [PATCH] Add web and console project. --- Cli/Cli.csproj | 37 +- Common.props | 40 + Common/Common.csproj | 37 +- Console/CommandLine/AnsiGenerator.cs | 259 +++ Console/CommandLine/Default.cs | 1724 +++++++++++++++++ Console/CommandLine/HighlightConsoleStyle.cs | 114 ++ Console/CommandLine/InfoRender.cs | 360 ++++ Console/CommandLine/JsonConsoleStyle.cs | 326 ++++ .../CommandLine/LinearGradientConsoleStyle.cs | 172 ++ Console/CommandLine/ProgressRender.cs | 222 +++ Console/CommandLine/ProgressStyle.cs | 198 ++ .../CommandLine/RepeatedColorConsoleStyle.cs | 191 ++ Console/CommandLine/Resource.Designer.cs | 126 ++ Console/CommandLine/Resource.de.resx | 141 ++ Console/CommandLine/Resource.en.resx | 141 ++ Console/CommandLine/Resource.es.resx | 141 ++ Console/CommandLine/Resource.fr.resx | 141 ++ Console/CommandLine/Resource.ja.resx | 141 ++ Console/CommandLine/Resource.ko.resx | 141 ++ Console/CommandLine/Resource.pt.resx | 141 ++ Console/CommandLine/Resource.resx | 141 ++ Console/CommandLine/Resource.ru.resx | 141 ++ Console/CommandLine/Resource.zh-Hans.resx | 141 ++ Console/CommandLine/Resource.zh-Hant.resx | 141 ++ Console/CommandLine/SelectionOptions.cs | 291 +++ Console/CommandLine/SelectionRender.cs | 867 +++++++++ Console/Console.csproj | 39 + Console/README.md | 122 ++ Demo/Demo.csproj | 19 +- Materials/cmd.png | Bin 0 -> 98962 bytes Materials/web.png | Bin 0 -> 93304 bytes Web/README.md | 19 + Web/Web.csproj | 32 + Web/Web/ControllerExtensions.cs | 913 +++++++++ WinKit.sln | 45 + docs/assets/badge_ASPNET_5_0.svg | 1 + docs/assets/badge_ASPNET_6_0.svg | 1 + docs/assets/badge_ASPNET_8_0.svg | 1 + docs/assets/badge_NET_5_Win10.svg | 1 - docs/assets/badge_NET_Fx_4_6.svg | 1 + docs/assets/badge_NET_Fx_4_6_1.svg | 1 + docs/assets/badge_NET_Fx_4_8.svg | 1 + docs/assets/bg_title.jpg | Bin 0 -> 36664 bytes docs/assets/chemistry.png | Bin 0 -> 28928 bytes docs/assets/cmd.png | Bin 0 -> 33226 bytes docs/assets/mime.png | Bin 0 -> 30891 bytes docs/assets/web.png | Bin 0 -> 31315 bytes docs/assets/wordmark.png | Bin 0 -> 42122 bytes 48 files changed, 7631 insertions(+), 80 deletions(-) create mode 100644 Common.props create mode 100644 Console/CommandLine/AnsiGenerator.cs create mode 100644 Console/CommandLine/Default.cs create mode 100644 Console/CommandLine/HighlightConsoleStyle.cs create mode 100644 Console/CommandLine/InfoRender.cs create mode 100644 Console/CommandLine/JsonConsoleStyle.cs create mode 100644 Console/CommandLine/LinearGradientConsoleStyle.cs create mode 100644 Console/CommandLine/ProgressRender.cs create mode 100644 Console/CommandLine/ProgressStyle.cs create mode 100644 Console/CommandLine/RepeatedColorConsoleStyle.cs create mode 100644 Console/CommandLine/Resource.Designer.cs create mode 100644 Console/CommandLine/Resource.de.resx create mode 100644 Console/CommandLine/Resource.en.resx create mode 100644 Console/CommandLine/Resource.es.resx create mode 100644 Console/CommandLine/Resource.fr.resx create mode 100644 Console/CommandLine/Resource.ja.resx create mode 100644 Console/CommandLine/Resource.ko.resx create mode 100644 Console/CommandLine/Resource.pt.resx create mode 100644 Console/CommandLine/Resource.resx create mode 100644 Console/CommandLine/Resource.ru.resx create mode 100644 Console/CommandLine/Resource.zh-Hans.resx create mode 100644 Console/CommandLine/Resource.zh-Hant.resx create mode 100644 Console/CommandLine/SelectionOptions.cs create mode 100644 Console/CommandLine/SelectionRender.cs create mode 100644 Console/Console.csproj create mode 100644 Console/README.md create mode 100644 Materials/cmd.png create mode 100644 Materials/web.png create mode 100644 Web/README.md create mode 100644 Web/Web.csproj create mode 100644 Web/Web/ControllerExtensions.cs create mode 100644 docs/assets/badge_ASPNET_5_0.svg create mode 100644 docs/assets/badge_ASPNET_6_0.svg create mode 100644 docs/assets/badge_ASPNET_8_0.svg delete mode 100644 docs/assets/badge_NET_5_Win10.svg create mode 100644 docs/assets/badge_NET_Fx_4_6.svg create mode 100644 docs/assets/badge_NET_Fx_4_6_1.svg create mode 100644 docs/assets/badge_NET_Fx_4_8.svg create mode 100644 docs/assets/bg_title.jpg create mode 100644 docs/assets/chemistry.png create mode 100644 docs/assets/cmd.png create mode 100644 docs/assets/mime.png create mode 100644 docs/assets/web.png create mode 100644 docs/assets/wordmark.png diff --git a/Cli/Cli.csproj b/Cli/Cli.csproj index a7b9158..3aae8f6 100644 --- a/Cli/Cli.csproj +++ b/Cli/Cli.csproj @@ -1,43 +1,24 @@  + + Exe net8.0;net7.0;net6.0 enable lwac Trivial.Web - Trivial - Kingcean Tuan - Nanchang Jinchen Software Co., Ltd. - 7.1.0 - 7.1.0.0 - 7.1.0.0 CLI for local web app. - Copyright (c) 2022 Kingcean Tuan. - MIT https://github.com/nuscien/winkit false true snupkg - https://github.com/nuscien/winkit - git - true logo.png cli lwa - README.md - ..\Materials\WinKit.ico - 10.0 - True - ..\Trivial.snk - - ..\bin\Debug\ - ..\bin\$(Configuration)\$(TargetFramework)\lwac.xml - - - - ..\bin\Release\ + + ..\bin\$(Configuration)\ ..\bin\$(Configuration)\$(TargetFramework)\lwac.xml @@ -51,16 +32,6 @@ - - - - - - - - - - diff --git a/Common.props b/Common.props new file mode 100644 index 0000000..952b896 --- /dev/null +++ b/Common.props @@ -0,0 +1,40 @@ + + + Trivial + Kingcean Tuan + Nanchang Jinchen Software Co., Ltd. + 7.2.0 + 7.2.0.0 + 7.2.0.0 + Copyright (c) 2018 Kingcean Tuan. + MIT + https://github.com/nuscien/trivial + git + true + README.md + 12.0 + True + ..\Trivial.snk + + + + NETOLDVER + + + + + + + + + + + + + + + + + + + diff --git a/Common/Common.csproj b/Common/Common.csproj index 7c572e1..82206e2 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -1,4 +1,7 @@  + + + net7.0-windows10.0.17763.0;net7.0-windows10.0.19041.0;net7.0-windows10.0.22000.0;net6.0-windows10.0.17763.0;net6.0-windows10.0.19041.0;net6.0-windows10.0.22000.0 10.0.17763.0 @@ -7,38 +10,15 @@ Trivial.WindowsKit win10-x86;win10-x64;win10-arm64 true - Trivial - Kingcean Tuan - Nanchang Jinchen Software Co., Ltd. - 7.1.0 - 7.1.0.0 - 7.1.0.0 Some advanced visual controls and utilities for Windows app. - Copyright (c) 2022 Kingcean Tuan. - MIT - https://github.com/nuscien/winkit - true true snupkg - https://github.com/nuscien/winkit - git - true logo.png ui tiles lwa - README.md - ..\Materials\WinKit.ico - 10.0 - True - ..\Trivial.snk - - - - ..\bin\Debug\ - ..\bin\$(Configuration)\$(TargetFramework)\Trivial.WindowsKit.xml - - ..\bin\Release\ + + ..\bin\$(Configuration)\ ..\bin\$(Configuration)\$(TargetFramework)\Trivial.WindowsKit.xml @@ -54,11 +34,6 @@ - - - - - @@ -81,8 +56,6 @@ - - diff --git a/Console/CommandLine/AnsiGenerator.cs b/Console/CommandLine/AnsiGenerator.cs new file mode 100644 index 0000000..50e08b5 --- /dev/null +++ b/Console/CommandLine/AnsiGenerator.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Trivial.CommandLine; + +/// +/// Code generator of ANSI escape sequences. +/// +internal static class AnsiCodeGenerator +{ + // https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences + + /// + /// The sign of escape. + /// + public const string Esc = "\u001b"; + + /// + /// Gets the ANSI escape sequences to set the foreground color. + /// + /// The color. + /// The specific ANSI escape sequences. + public static string Foreground(ConsoleColor? color) + => color.HasValue ? color.Value switch + { + ConsoleColor.Black => $"{Esc}[30m", + ConsoleColor.White => $"{Esc}[97m", + ConsoleColor.DarkRed => $"{Esc}[31m", + ConsoleColor.DarkGreen => $"{Esc}[32m", + ConsoleColor.DarkYellow => $"{Esc}[33m", + ConsoleColor.DarkBlue => $"{Esc}[34m", + ConsoleColor.DarkMagenta => $"{Esc}[35m", + ConsoleColor.DarkCyan => $"{Esc}[36m", + ConsoleColor.DarkGray => $"{Esc}[90m", + ConsoleColor.Red => $"{Esc}[91m", + ConsoleColor.Green => $"{Esc}[92m", + ConsoleColor.Yellow => $"{Esc}[93m", + ConsoleColor.Blue => $"{Esc}[94m", + ConsoleColor.Magenta => $"{Esc}[95m", + ConsoleColor.Cyan => $"{Esc}[96m", + ConsoleColor.Gray => $"{Esc}[37m", + _ => string.Empty + } : string.Empty; + + /// + /// Gets the ANSI escape sequences to set the foreground color. + /// + /// The red. + /// The green. + /// The blue. + /// The specific ANSI escape sequences. + public static string Foreground(byte r, byte g, byte b) + => $"{Esc}[38;2;{r};{g};{b}m"; + + /// + /// Gets the ANSI escape sequences to set the foreground color. + /// + /// The color. + /// The specific ANSI escape sequences. + public static string Foreground(System.Drawing.Color color) + => $"{Esc}[38;2;{color.R};{color.G};{color.B}m"; + + /// + /// Gets the ANSI escape sequences to set the foreground color. + /// + /// true if resets color; otherwise, false. + /// The specific ANSI escape sequences. + public static string Foreground(bool reset) + => reset ? $"{Esc}[39m" : string.Empty; + + /// + /// Gets the ANSI escape sequences to set the background color. + /// + /// The color. + /// The specific ANSI escape sequences. + public static string Background(ConsoleColor? color) + => color.HasValue ? color.Value switch + { + ConsoleColor.Black => $"{Esc}[40m", + ConsoleColor.White => $"{Esc}[107m", + ConsoleColor.DarkRed => $"{Esc}[41m", + ConsoleColor.DarkGreen => $"{Esc}[42m", + ConsoleColor.DarkYellow => $"{Esc}[43m", + ConsoleColor.DarkBlue => $"{Esc}[44m", + ConsoleColor.DarkMagenta => $"{Esc}[45m", + ConsoleColor.DarkCyan => $"{Esc}[46m", + ConsoleColor.DarkGray => $"{Esc}[100m", + ConsoleColor.Red => $"{Esc}[101m", + ConsoleColor.Green => $"{Esc}[102m", + ConsoleColor.Yellow => $"{Esc}[103m", + ConsoleColor.Blue => $"{Esc}[104m", + ConsoleColor.Magenta => $"{Esc}[105m", + ConsoleColor.Cyan => $"{Esc}[106m", + ConsoleColor.Gray => $"{Esc}[47m", + _ => string.Empty + } : string.Empty; + + /// + /// Gets the ANSI escape sequences to set the background color. + /// + /// The red. + /// The green. + /// The blue. + /// The specific ANSI escape sequences. + public static string Background(byte r, byte g, byte b) + => $"{Esc}[48;2;{r};{g};{b}m"; + + /// + /// Gets the ANSI escape sequences to set the background color. + /// + /// The color. + /// The specific ANSI escape sequences. + public static string Background(System.Drawing.Color color) + => $"{Esc}[48;2;{color.R};{color.G};{color.B}m"; + + /// + /// Gets the ANSI escape sequences to set the foreground color. + /// + /// true if resets color; otherwise, false. + /// The specific ANSI escape sequences. + public static string Background(bool reset) + => reset ? $"{Esc}[49m" : string.Empty; + + public static string AttributesOff() => $"{Esc}[0m"; + public static string Blink(bool enable) => enable ? $"{Esc}[5m" : $"{Esc}[25m"; + public static string Bold(bool enable) => enable ? $"{Esc}[1m" : $"{Esc}[22m"; + public static string TextHidden() => $"{Esc}[8m"; + public static string Reverse(bool enable) => enable ? $"{Esc}[7m" : $"{Esc}[27m"; + public static string Italic(bool enable) => enable ? $"{Esc}[3m" : $"{Esc}[23m"; + public static string Underline(bool enable) => enable ? $"{Esc}[4m" : $"{Esc}[24m"; + public static string Strikeout(bool enable) => enable ? $"{Esc}[9m" : $"{Esc}[29m"; + + public static string MoveCursorX(int columns) + { + if (columns == 0) return string.Empty; + return columns > 0 ? $"{Esc}[{columns}C" : $"{Esc}[{-columns}D"; + } + + public static string MoveCursorY(int lines) + { + if (lines == 0) return string.Empty; + return lines > 0 ? $"{Esc}[{lines}B" : $"{Esc}[{-lines}A"; + } + + public static string MoveCursorBy(int x, int y) + => $"{MoveCursorX(x)}{MoveCursorY(y)}"; + + public static string MoveCursorNextLine(int line = 1) + => $"{Esc}[{line}E"; + + public static string MoveCursorTo(int left, int top = -1) + => top >= 0 + ? $"{Esc}[{top + 1};{(left >= 0 ? (left + 1).ToString("g") : string.Empty)}H" + : $"{Esc}[{(left >= 0 ? (left + 1).ToString("g") : string.Empty)}G"; + + public static string CursorVisibility(bool show) + => show ? $"{Esc}[?25h" : $"{Esc}[?25l"; + + public static string ScrollBy(int step) + { + if (step == 0) return string.Empty; + var r = step > 0 ? $"{Esc}[T" : $"{Esc}[S"; + var i = Math.Abs(step); + if (i == 1) return r; + var s = new StringBuilder(r); + for (var j = 1; j < i; j++) + { + s.Append(r); + } + + return s.ToString(); + } + + /// + /// Code to clear lines. + /// + public static string Clear(StyleConsole.RelativeAreas area) + => area switch + { + StyleConsole.RelativeAreas.Line => $"{Esc}[2K", + StyleConsole.RelativeAreas.ToBeginningOfLine => $"{Esc}[1K", + StyleConsole.RelativeAreas.ToEndOfLine => $"{Esc}[K", + StyleConsole.RelativeAreas.EntireScreen => $"{Esc}[2J", + StyleConsole.RelativeAreas.ToBeginningOfScreen => $"{Esc}[1J", + StyleConsole.RelativeAreas.ToEndOfScreen => $"{Esc}[J", + StyleConsole.RelativeAreas.EntireBuffer => $"{Esc}[3J", + _ => string.Empty + }; + + public static string SaveCursorPosition() => $"{Esc}7"; + + public static string RestoreCursorPosition() => $"{Esc}8"; + + public static string Remove(int count = 1) + { + if (count == 0) return string.Empty; + return count > 0 ? $"{Esc}[{count}X" : $"{Esc}[{-count}P"; + } + + public static ConsoleColor ToConsoleColor(System.Drawing.Color color) + => ToConsoleColor(color.R, color.G, color.B); + + public static ConsoleColor ToConsoleColor(byte r, byte g, byte b) + { + if (r >= 220 && g >= 220 && b >= 220) + return ConsoleColor.White; + if (r <= 48 && g <= 48 && b <= 48) + return ConsoleColor.Black; + var isLight = r >= 192 || g >= 192 || b >= 192; + var rank = new Maths.RankResult3(r, g, b, CompareColorChannel); + var s = $"{rank.RankFor1}{rank.RankFor2}{rank.RankFor3}"; + if (s.Contains('3')) + { + var single = rank.Number1 - rank.Number2 >= rank.Number2 - rank.Number3; + switch (s) + { + case "123": + s = single ? "122" : "112"; + break; + case "132": + s = single ? "122" : "121"; + break; + case "312": + s = single ? "212" : "211"; + break; + case "213": + s = single ? "212" : "112"; + break; + case "321": + s = single ? "221" : "211"; + break; + case "231": + s = single ? "221" : "121"; + break; + } + } + + return s switch + { + "122" => isLight ? ConsoleColor.Red : ConsoleColor.DarkRed, + "212" => isLight ? ConsoleColor.Green : ConsoleColor.DarkBlue, + "221" => isLight ? ConsoleColor.Blue : ConsoleColor.DarkBlue, + "112" => isLight ? ConsoleColor.Yellow : ConsoleColor.DarkYellow, + "121" => isLight ? ConsoleColor.Magenta : ConsoleColor.DarkMagenta, + "211" => isLight ? ConsoleColor.Cyan : ConsoleColor.DarkCyan, + _ => isLight ? ConsoleColor.Gray : ConsoleColor.DarkGray + }; + } + + private static int CompareColorChannel(int a, int b) + { + var diff = a - b; + if (diff > -48 && diff < 48) return 0; + return diff; + } +} diff --git a/Console/CommandLine/Default.cs b/Console/CommandLine/Default.cs new file mode 100644 index 0000000..49f3ace --- /dev/null +++ b/Console/CommandLine/Default.cs @@ -0,0 +1,1724 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Security; +using System.Text; +using System.Threading.Tasks; + +using Trivial.Collection; +using Trivial.Security; +using Trivial.Tasks; +using Trivial.Text; + +namespace Trivial.CommandLine; + +/// +/// The command line interface. +/// +public static class DefaultConsole +{ + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The text content. + public static void Write(ConsoleText content) + => StyleConsole.Default.Write(content); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The text content 1. + /// The text content 2. + /// The additional text content collection. + public static void Write(ConsoleText content1, ConsoleText content2, params ConsoleText[] additionalContext) + => StyleConsole.Default.Write(content1, content2, additionalContext); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The text content collection. + public static void Write(IEnumerable content) + => StyleConsole.Default.Write(content); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void Write(string s, params object[] args) + => StyleConsole.Default.Write(s, args); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void Write(ConsoleTextStyle style, string s, params object[] args) + => StyleConsole.Default.Write(style, s, args); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void Write(ConsoleColor foreground, string s, params object[] args) + => StyleConsole.Default.Write(foreground, s, args); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, string s, params object[] args) + => StyleConsole.Default.Write(foreground, background, s, args); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void Write(Color foreground, string s, params object[] args) + => StyleConsole.Default.Write(foreground, s, args); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void Write(Color foreground, Color background, string s, params object[] args) + => StyleConsole.Default.Write(foreground, background, s, args); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The style. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void Write(IConsoleTextPrettier style, string s, params object[] args) + => StyleConsole.Default.Write(style, s, args); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// A composite format string to output. + public static void Write(StringBuilder s) + => StyleConsole.Default.Write(s); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A composite format string to output. + public static void Write(ConsoleTextStyle style, StringBuilder s) + => StyleConsole.Default.Write(style, s); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + public static void Write(ConsoleColor foreground, StringBuilder s) + => StyleConsole.Default.Write(foreground, s); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, StringBuilder s) + => StyleConsole.Default.Write(foreground, background, s); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + public static void Write(Color foreground, StringBuilder s) + => StyleConsole.Default.Write(foreground, s); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + public static void Write(Color foreground, Color background, StringBuilder s) + => StyleConsole.Default.Write(foreground, background, s); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The style. + /// A composite format string to output. + public static void Write(IConsoleTextPrettier style, StringBuilder s) + => StyleConsole.Default.Write(style, s); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// A composite format string to output. + public static void Write(SecureString s) + => StyleConsole.Default.Write(s.ToUnsecureString()); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A composite format string to output. + public static void Write(ConsoleTextStyle style, SecureString s) + => StyleConsole.Default.Write(style, s.ToUnsecureString()); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + public static void Write(ConsoleColor foreground, SecureString s) + => StyleConsole.Default.Write(foreground, s.ToUnsecureString()); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, SecureString s) + => StyleConsole.Default.Write(foreground, background, s.ToUnsecureString()); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// A number to output. + public static void Write(int number) + => StyleConsole.Default.Write(number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void Write(int number, string format) + => StyleConsole.Default.Write(number, format); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A number to output. + public static void Write(ConsoleTextStyle style, int number) + => StyleConsole.Default.Write(style, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void Write(ConsoleTextStyle style, int number, string format) + => StyleConsole.Default.Write(style, number, format); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void Write(ConsoleColor foreground, int number) + => StyleConsole.Default.Write(foreground, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void Write(ConsoleColor foreground, int number, string format) + => StyleConsole.Default.Write(foreground, number, format); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, int number) + => StyleConsole.Default.Write(foreground, background, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, int number, string format) + => StyleConsole.Default.Write(foreground, background, number, format); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// A number to output. + public static void Write(long number) + => StyleConsole.Default.Write(number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A number to output. + public static void Write(ConsoleTextStyle style, long number) + => StyleConsole.Default.Write(style, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void Write(ConsoleColor foreground, long number) + => StyleConsole.Default.Write(foreground, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, long number) + => StyleConsole.Default.Write(foreground, background, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// A number to output. + public static void Write(ulong number) + => StyleConsole.Default.Write(number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A number to output. + public static void Write(ConsoleTextStyle style, ulong number) + => StyleConsole.Default.Write(style, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void Write(ConsoleColor foreground, ulong number) + => StyleConsole.Default.Write(foreground, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, ulong number) + => StyleConsole.Default.Write(foreground, background, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// A number to output. + public static void Write(float number) + => StyleConsole.Default.Write(number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A number to output. + public static void Write(ConsoleTextStyle style, float number) + => StyleConsole.Default.Write(style, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void Write(ConsoleColor foreground, float number) + => StyleConsole.Default.Write(foreground, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, float number) + => StyleConsole.Default.Write(foreground, background, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// A number to output. + public static void Write(decimal number) + => StyleConsole.Default.Write(number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A number to output. + public static void Write(ConsoleTextStyle style, decimal number) + => StyleConsole.Default.Write(style, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void Write(ConsoleColor foreground, decimal number) + => StyleConsole.Default.Write(foreground, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, decimal number) + => StyleConsole.Default.Write(foreground, background, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// A number to output. + public static void Write(double number) + => StyleConsole.Default.Write(number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void Write(double number, string format) + => StyleConsole.Default.Write(number, format); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A number to output. + public static void Write(ConsoleTextStyle style, double number) + => StyleConsole.Default.Write(style, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void Write(ConsoleTextStyle style, double number, string format) + => StyleConsole.Default.Write(style, number, format); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void Write(ConsoleColor foreground, double number) + => StyleConsole.Default.Write(foreground, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void Write(ConsoleColor foreground, double number, string format) + => StyleConsole.Default.Write(foreground, number, format); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, double number) + => StyleConsole.Default.Write(foreground, background, number); + + /// + /// Writes the specified number to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, double number, string format) + => StyleConsole.Default.Write(foreground, background, number, format); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void Write(char[] value, int start = 0, int? count = null) + => StyleConsole.Default.Write(value, start, count); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void Write(ConsoleTextStyle style, char[] value, int start = 0, int? count = null) + => StyleConsole.Default.Write(style, value, start, count); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void Write(ConsoleColor foreground, char[] value, int start = 0, int? count = null) + => StyleConsole.Default.Write(foreground, value, start, count); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, char[] value, int start = 0, int? count = null) + => StyleConsole.Default.Write(foreground, background, value, start, count); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void Write(IConsoleTextPrettier style, char[] value, int start = 0, int? count = null) + => StyleConsole.Default.Write(style, value, start, count); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The value to write. + /// The number of times to append value. + public static void Write(char value, int repeatCount = 1) + => StyleConsole.Default.Write(value, repeatCount); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The content style. + /// The value to write. + /// The number of times to append value. + public static void Write(ConsoleTextStyle style, char value, int repeatCount = 1) + => StyleConsole.Default.Write(style, value, repeatCount); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The value to write. + /// The number of times to append value. + public static void Write(ConsoleColor foreground, char value, int repeatCount = 1) + => StyleConsole.Default.Write(foreground, value, repeatCount); + + /// + /// Writes the specified string value to the standard output stream. + /// Note it may not flush immediately. + /// + /// The style. + /// The value to write. + /// The number of times to append value. + public static void Write(IConsoleTextPrettier style, char value, int repeatCount = 1) + => StyleConsole.Default.Write(style, value, repeatCount); + + /// + /// Writes the specified data to the standard output stream. + /// Note it may not flush immediately. + /// + /// A representation model. + public static void Write(IConsoleTextCreator model) + => StyleConsole.Default.Write(model); + + /// + /// Writes the specified data to the standard output stream. + /// Note it may not flush immediately. + /// + /// The type of data model. + /// The style. + /// A data model. + public static void Write(IConsoleTextCreator style, T data) + => StyleConsole.Default.Write(style, data); + + /// + /// Writes the specified data to the standard output stream. + /// Note it may not flush immediately. + /// + /// The type of data model. + /// The additional options. + /// The style. + /// A data model. + /// The additional options. + public static void Write(IConsoleTextCreator style, TData data, TOptions options) + => StyleConsole.Default.Write(style, data, options); + + /// + /// Writes the specified characters to the standard output stream. + /// Note it may not flush immediately. + /// + /// The foreground color. + /// The background color. + /// The value to write. + /// The number of times to append value. + public static void Write(ConsoleColor? foreground, ConsoleColor? background, char value, int repeatCount = 1) + => StyleConsole.Default.Write(foreground, background, value, repeatCount); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The text content. + public static void WriteLine(ConsoleText content = null) + => StyleConsole.Default.WriteLine(content); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The text content 1. + /// The text content 2. + /// The additional text content collection. + public static void WriteLine(ConsoleText content1, ConsoleText content2, params ConsoleText[] additionalContext) + => StyleConsole.Default.WriteLine(content1, content2, additionalContext); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The text content collection. + public static void WriteLine(IEnumerable content) + => StyleConsole.Default.WriteLine(content); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void WriteLine(string s, params object[] args) + => StyleConsole.Default.WriteLine(s, args); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// + /// The content style. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void WriteLine(ConsoleTextStyle style, string s, params object[] args) + => StyleConsole.Default.WriteLine(style, s, args); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void WriteLine(ConsoleColor foreground, string s, params object[] args) + => StyleConsole.Default.WriteLine(foreground, s, args); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, string s, params object[] args) + => StyleConsole.Default.WriteLine(foreground, background, s, args); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void WriteLine(Color foreground, string s, params object[] args) + => StyleConsole.Default.WriteLine(foreground, s, args); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void WriteLine(Color foreground, Color background, string s, params object[] args) + => StyleConsole.Default.WriteLine(foreground, background, s, args); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The style. + /// A composite format string to output. + /// An object array that contains zero or more objects to format. + /// format is invalid. -or- The index of a format item is less than zero, or greater than or equal to the length of the args array. + public static void WriteLine(IConsoleTextPrettier style, string s, params object[] args) + => StyleConsole.Default.WriteLine(style, s, args); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A composite format string to output. + public static void WriteLine(StringBuilder s) + => StyleConsole.Default.WriteLine(s); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// + /// The content style. + /// A composite format string to output. + public static void WriteLine(ConsoleTextStyle style, StringBuilder s) + => StyleConsole.Default.WriteLine(style, s); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + public static void WriteLine(ConsoleColor foreground, StringBuilder s) + => StyleConsole.Default.WriteLine(foreground, s); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, StringBuilder s) + => StyleConsole.Default.WriteLine(foreground, background, s); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + public static void WriteLine(Color foreground, StringBuilder s) + => StyleConsole.Default.WriteLine(foreground, s); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + public static void WriteLine(Color foreground, Color background, StringBuilder s) + => StyleConsole.Default.WriteLine(foreground, background, s); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The style. + /// A composite format string to output. + public static void WriteLine(IConsoleTextPrettier style, StringBuilder s) + => StyleConsole.Default.WriteLine(style, s?.ToString()); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A composite format string to output. + public static void WriteLine(SecureString s) + => StyleConsole.Default.WriteLine(s?.ToUnsecureString()); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// + /// The content style. + /// A composite format string to output. + public static void WriteLine(ConsoleTextStyle style, SecureString s) + => StyleConsole.Default.WriteLine(style, s?.ToUnsecureString()); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A composite format string to output. + public static void WriteLine(ConsoleColor foreground, SecureString s) + => StyleConsole.Default.WriteLine(foreground, s?.ToUnsecureString()); + + /// + /// Writes the specified string value, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A composite format string to output. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, SecureString s) + => StyleConsole.Default.WriteLine(foreground, background, s.ToUnsecureString()); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A number to output. + public static void WriteLine(int number) + => StyleConsole.Default.WriteLine(number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void WriteLine(int number, string format) + => StyleConsole.Default.WriteLine(number, format); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// A number to output. + public static void WriteLine(ConsoleTextStyle style, int number) + => StyleConsole.Default.WriteLine(style, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void WriteLine(ConsoleTextStyle style, int number, string format) + => StyleConsole.Default.WriteLine(style, number, format); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void WriteLine(ConsoleColor foreground, int number) + => StyleConsole.Default.WriteLine(foreground, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void WriteLine(ConsoleColor foreground, int number, string format) + => StyleConsole.Default.WriteLine(foreground, number, format); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, int number) + => StyleConsole.Default.WriteLine(foreground, background, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, int number, string format) + => StyleConsole.Default.WriteLine(foreground, background, number, format); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A number to output. + public static void WriteLine(long number) + => StyleConsole.Default.WriteLine(number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// A number to output. + public static void WriteLine(ConsoleTextStyle style, long number) + => StyleConsole.Default.WriteLine(style, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void WriteLine(ConsoleColor foreground, long number) + => StyleConsole.Default.WriteLine(foreground, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, long number) + => StyleConsole.Default.WriteLine(foreground, background, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A number to output. + public static void WriteLine(ulong number) + => StyleConsole.Default.WriteLine(number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// A number to output. + public static void WriteLine(ConsoleTextStyle style, ulong number) + => StyleConsole.Default.WriteLine(style, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void WriteLine(ConsoleColor foreground, ulong number) + => StyleConsole.Default.WriteLine(foreground, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, ulong number) + => StyleConsole.Default.WriteLine(foreground, background, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A number to output. + public static void WriteLine(float number) + => StyleConsole.Default.WriteLine(number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// A number to output. + public static void WriteLine(ConsoleTextStyle style, float number) + => StyleConsole.Default.WriteLine(style, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void WriteLine(ConsoleColor foreground, float number) + => StyleConsole.Default.WriteLine(foreground, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, float number) + => StyleConsole.Default.WriteLine(foreground, background, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A number to output. + public static void WriteLine(decimal number) + => StyleConsole.Default.WriteLine(number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// A number to output. + public static void WriteLine(ConsoleTextStyle style, decimal number) + => StyleConsole.Default.WriteLine(style, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void WriteLine(ConsoleColor foreground, decimal number) + => StyleConsole.Default.WriteLine(foreground, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, decimal number) + => StyleConsole.Default.WriteLine(foreground, background, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A number to output. + public static void WriteLine(double number) + => StyleConsole.Default.WriteLine(number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void WriteLine(double number, string format) + => StyleConsole.Default.WriteLine(number, format); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// A number to output. + public static void WriteLine(ConsoleTextStyle style, double number) + => StyleConsole.Default.WriteLine(style, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void WriteLine(ConsoleTextStyle style, double number, string format) + => StyleConsole.Default.WriteLine(style, number, format); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A number to output. + public static void WriteLine(ConsoleColor foreground, double number) + => StyleConsole.Default.WriteLine(foreground, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void WriteLine(ConsoleColor foreground, double number, string format) + => StyleConsole.Default.WriteLine(foreground, number, format); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, double number) + => StyleConsole.Default.WriteLine(foreground, background, number); + + /// + /// Writes the specified number, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// A number to output. + /// A standard or custom numeric format string. + /// format is invalid or not supported. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, double number, string format) + => StyleConsole.Default.WriteLine(foreground, background, number, format); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void WriteLine(char[] value, int start = 0, int? count = null) + => StyleConsole.Default.WriteLine(value, start, count); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void WriteLine(ConsoleTextStyle style, char[] value, int start = 0, int? count = null) + => StyleConsole.Default.WriteLine(style, value, start, count); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void WriteLine(ConsoleColor foreground, char[] value, int start = 0, int? count = null) + => StyleConsole.Default.WriteLine(foreground, value, start, count); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, char[] value, int start = 0, int? count = null) + => StyleConsole.Default.WriteLine(foreground, background, value, start, count); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// The value to write. + /// The starting position in value. + /// The number of characters to write. + public static void WriteLine(IConsoleTextPrettier style, char[] value, int start = 0, int? count = null) + => StyleConsole.Default.WriteLine(style, value, start, count); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The value to write. + /// The number of times to append value. + public static void WriteLine(char value, int repeatCount = 1) + => StyleConsole.Default.WriteLine(value, repeatCount); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The content style. + /// The value to write. + /// The number of times to append value. + public static void WriteLine(ConsoleTextStyle style, char value, int repeatCount = 1) + => StyleConsole.Default.WriteLine(style, value, repeatCount); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The value to write. + /// The number of times to append value. + public static void WriteLine(ConsoleColor foreground, char value, int repeatCount = 1) + => StyleConsole.Default.WriteLine(foreground, value, repeatCount); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The style. + /// The value to write. + /// The number of times to append value. + public static void WriteLine(IConsoleTextPrettier style, char value, int repeatCount = 1) + => StyleConsole.Default.WriteLine(style, value, repeatCount); + + /// + /// Writes the specified characters, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The foreground color. + /// The background color. + /// The value to write. + /// The number of times to append value. + public static void WriteLine(ConsoleColor? foreground, ConsoleColor? background, char value, int repeatCount = 1) + => StyleConsole.Default.WriteLine(foreground, background, value, repeatCount); + + /// + /// Writes an exception, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The exception. + /// true if output stack trace; otherwise, false. + public static void WriteLine(Exception ex, bool stackTrace = false) + => StyleConsole.Default.WriteLine(new ConsoleTextStyle(ConsoleColor.Red), null as ConsoleTextStyle, ex, stackTrace); + + /// + /// Writes an exception, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The exception. + /// The style of header. + /// The style of details. + /// true if output stack trace; otherwise, false. + public static void WriteLine(ConsoleTextStyle captionStyle, ConsoleTextStyle messageStyle, Exception ex, bool stackTrace = false) + => StyleConsole.Default.WriteLine(captionStyle, messageStyle, ex, stackTrace); + + /// + /// Writes an exception, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The error information. + public static void WriteLine(Data.ErrorMessageResult ex) + => StyleConsole.Default.WriteLine(new ConsoleTextStyle(ConsoleColor.Red), null as ConsoleTextStyle, ex); + + /// + /// Writes an exception, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The error information. + /// The style of header. + /// The style of details. + public static void WriteLine(ConsoleTextStyle captionStyle, ConsoleTextStyle messageStyle, Data.ErrorMessageResult ex) + => StyleConsole.Default.WriteLine(captionStyle, messageStyle, ex); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The JSON instance. + public static void WriteLine(IJsonDataNode json) + => StyleConsole.Default.WriteLine(new JsonConsoleStyle().CreateTextCollection(json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The style. + /// The JSON instance. + public static void WriteLine(JsonConsoleStyle style, IJsonDataNode json) + => StyleConsole.Default.WriteLine((style ?? new JsonConsoleStyle()).CreateTextCollection(json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The JSON instance. + public static void WriteLine(System.Text.Json.Nodes.JsonObject json) + => StyleConsole.Default.WriteLine(new JsonConsoleStyle().CreateTextCollection(json == null ? null : (JsonObjectNode)json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The style. + /// The JSON instance. + public static void WriteLine(JsonConsoleStyle style, System.Text.Json.Nodes.JsonObject json) + => StyleConsole.Default.WriteLine((style ?? new JsonConsoleStyle()).CreateTextCollection(json == null ? null : (JsonObjectNode)json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The JSON instance. + public static void WriteLine(IJsonObjectHost json) + => StyleConsole.Default.WriteLine(new JsonConsoleStyle().CreateTextCollection(json?.ToJson(), 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The style. + /// The JSON instance. + public static void WriteLine(JsonConsoleStyle style, IJsonObjectHost json) + => StyleConsole.Default.WriteLine((style ?? new JsonConsoleStyle()).CreateTextCollection(json?.ToJson(), 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The JSON instance. + public static void WriteLine(System.Text.Json.Nodes.JsonArray json) + => StyleConsole.Default.WriteLine(new JsonConsoleStyle().CreateTextCollection(json == null ? null : (JsonArrayNode)json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The style. + /// The JSON instance. + public static void WriteLine(JsonConsoleStyle style, System.Text.Json.Nodes.JsonArray json) + => StyleConsole.Default.WriteLine((style ?? new JsonConsoleStyle()).CreateTextCollection(json == null ? null : (JsonArrayNode)json, 0)); + + /// + /// Writes the specified data, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// A representation model. + public static void WriteLine(IConsoleTextCreator model) + => StyleConsole.Default.WriteLine(model); + + /// + /// Writes the specified data, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The type of data model. + /// The style. + /// A data model. + public static void WriteLine(IConsoleTextCreator style, T data) + => StyleConsole.Default.WriteLine(style, data); + + /// + /// Writes the specified data, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The type of data model. + /// The additional options. + /// The style. + /// A data model. + /// The additional options. + public static void WriteLine(IConsoleTextCreator style, TData data, TOptions options) + => StyleConsole.Default.WriteLine(style, data, options); + + /// + /// Writes a progress component, followed by the current line terminator, to the standard output stream. + /// + /// The options. + /// The progress result. + public static OneProgress WriteLine(ConsoleProgressStyle style) + => StyleConsole.Default.WriteLine(style, null); + + /// + /// Writes a progress component, followed by the current line terminator, to the standard output stream. + /// + /// The caption; or null if no caption. It will be better if it is less than 20 characters. + /// The progress size. + /// The progress kind. + /// The progress result. + public static OneProgress WriteLine(ConsoleProgressStyle.Sizes progressSize, string caption, ConsoleProgressStyle.Kinds kind = ConsoleProgressStyle.Kinds.Full) + => StyleConsole.Default.WriteLine(progressSize, caption, kind); + + /// + /// Writes a progress component, followed by the current line terminator, to the standard output stream. + /// + /// The progress size. + /// The progress kind. + /// The progress result. + public static OneProgress WriteLine(ConsoleProgressStyle.Sizes progressSize, ConsoleProgressStyle.Kinds kind = ConsoleProgressStyle.Kinds.Full) + => StyleConsole.Default.WriteLine(progressSize, kind); + + /// + /// Writes a progress component, followed by the current line terminator, to the standard output stream. + /// + /// The caption; or null if no caption. It will be better if it is less than 20 characters. + /// The style. + /// The progress result. + public static OneProgress WriteLine(ConsoleProgressStyle style, string caption) + => StyleConsole.Default.WriteLine(style, caption); + + /// + /// Writes the specific lines to the standard output stream. + /// + /// The count of line. + public static void WriteLines(int count) + => StyleConsole.Default.WriteLines(count); + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The text content collection. + public static void WriteLines(IEnumerable content) + => StyleConsole.Default.WriteLines(content); + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The text content. + /// The additional text content collection. + public static void WriteLines(ConsoleText content, params ConsoleText[] additionalContext) + => StyleConsole.Default.WriteLines(content, additionalContext); + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The string collection to write. Each one in a line. + public static void WriteLines(IEnumerable col) + => StyleConsole.Default.WriteLines(col); + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The content style. + /// The string collection to write. Each one in a line. + public static void WriteLines(ConsoleTextStyle style, IEnumerable col) + => StyleConsole.Default.WriteLines(style, col); + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The foreground color of the console. + /// The string collection to write. Each one in a line. + public static void WriteLines(ConsoleColor foreground, IEnumerable col) + => StyleConsole.Default.WriteLines(foreground, col); + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The foreground color of the console. + /// The background color. + /// The string collection to write. Each one in a line. + public static void WriteLines(ConsoleColor foreground, ConsoleColor background, IEnumerable col) + => StyleConsole.Default.WriteLines(foreground, background, col); + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The string collection to write. Each one in a line. + /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element. + public static void WriteLines(IEnumerable col, Func selector) + { + if (col == null) return; + if (selector == null) selector = (ele, i) => ele?.ToString(); + StyleConsole.Default.WriteLines(col.Select(selector)); + } + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The foreground color of the console. + /// The string collection to write. Each one in a line. + /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element. + public static void WriteLines(ConsoleColor foreground, IEnumerable col, Func selector) + { + if (col == null) return; + if (selector == null) selector = (ele, i) => ele?.ToString(); + StyleConsole.Default.WriteLines(foreground, col.Select(selector)); + } + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The string collection to write. Each one in a line. + /// A transform function to apply to each element. + public static void WriteLines(IEnumerable col, Func selector) + { + if (col == null) return; + if (selector == null) selector = ele => ele?.ToString(); + StyleConsole.Default.WriteLines(col.Select(selector)); + } + + /// + /// Writes the current line terminator for each item, to the standard output stream. + /// + /// The foreground color of the console. + /// The string collection to write. Each one in a line. + /// A transform function to apply to each element. + public static void WriteLines(ConsoleColor foreground, IEnumerable col, Func selector) + { + if (col == null) return; + if (selector == null) selector = ele => ele?.ToString(); + StyleConsole.Default.WriteLines(foreground, col.Select(selector)); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The collection data. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(SelectionData collection, SelectionConsoleOptions options = null) + => StyleConsole.Default.Select(collection, options); + + /// + /// Writes a collection of item for selecting. + /// + /// The collection data. + /// The converter. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(IEnumerable collection, Func> convert, SelectionConsoleOptions options = null) + => StyleConsole.Default.Select(collection, convert, options); + + /// + /// Writes a collection of item for selecting. + /// + /// The collection data. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(IEnumerable> collection, SelectionConsoleOptions options = null) + => StyleConsole.Default.Select(collection, options); + + /// + /// Writes a collection of item for selecting. + /// + /// The parent foler path. + /// The selection display options. + /// The search string to match against the names of directories and files. This parameter can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn't support regular expressions. + /// The result of selection. + /// searchPattern contains one or more invalid characters defined by the System.IO.Path.GetInvalidPathChars method. + /// The specified path is invalid (for example, it is on an unmapped drive). + /// The caller does not have the required permission. + public static SelectionResult Select(DirectoryInfo path, SelectionConsoleOptions options = null, string searchPattern = null) + => StyleConsole.Default.Select(path, options, searchPattern); + + /// + /// Writes a collection of item for selecting. + /// + /// The parent foler path. + /// A function to test each element for a condition. + /// The selection display options. + /// The result of selection. + /// The specified path is invalid (for example, it is on an unmapped drive). + /// The caller does not have the required permission. + public static SelectionResult Select(DirectoryInfo path, Func predicate, SelectionConsoleOptions options = null) + => StyleConsole.Default.Select(path, predicate, options); + + /// + /// Writes a collection of item for selecting. + /// + /// The type of data. + /// The collection data. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(SelectionData collection, SelectionConsoleOptions options = null) + => StyleConsole.Default.Select(collection, options); + + /// + /// Writes a collection of item for selecting. + /// + /// The collection data. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(IEnumerable collection, SelectionConsoleOptions options = null) + => StyleConsole.Default.Select(collection, options); + + /// + /// Flushes all data. + /// + public static void Flush() + => StyleConsole.Default.Flush(); + + /// + /// Clears output cache. + /// + public static void ClearOutputCache() + => StyleConsole.Default.ClearOutputCache(); + + /// + /// Enters a backspace to console to remove the last charactor. + /// + /// The count of the charactor to remove from end. + /// true if just only move cursor back and keep output; otherwise, false. + public static void Backspace(int count = 1, bool doNotRemoveOutput = false) + => StyleConsole.Default.Backspace(count, doNotRemoveOutput); + + /// + /// Enters backspaces to console to remove the charactors to the beginning of the line. + /// + public static void BackspaceToBeginning() + => StyleConsole.Default.BackspaceToBeginning(); + + /// + /// Reads the next line of characters from the standard input stream. + /// + /// The next line of characters from the input stream, or null if no more lines are available. + /// An I/O error occurred. + /// There is insufficient memory to allocate a buffer for the returned string. + /// The number of characters in the next line of characters is greater than max value of 32-bit integer. + public static string ReadLine() + => StyleConsole.Default.ReadLine(); + + /// + /// Obtains the next character or function key pressed by the user. The pressed key is optionally displayed in the console window. + /// + /// Determines whether to display the pressed key in the console window. true to not display the pressed key; otherwise, false. + /// The next line of characters from the input stream, or null if no more lines are available. + /// An I/O error occurred. + /// The input stream is redirected from the one other than the console. + public static ConsoleKeyInfo ReadKey(bool intercept = false) + => StyleConsole.Default.ReadKey(intercept); + + /// + /// Obtains the password pressed by the user. + /// + /// + /// The password. + /// + public static SecureString ReadPassword() + => StyleConsole.Default.ReadPassword(null, null); + + /// + /// Obtains the password pressed by the user. + /// + /// The optional charactor to output to replace the original one, such as *. + /// true if do not follow the line terminator after typing the password; otherwise, false. + /// + /// The password. + /// + public static SecureString ReadPassword(char replaceChar, bool inline = false) + => StyleConsole.Default.ReadPassword(null, replaceChar, inline); + + /// + /// Obtains the password pressed by the user. + /// + /// The replace charactor color. + /// The optional charactor to output to replace the original one, such as *. + /// true if do not follow the line terminator after typing the password; otherwise, false. + /// + /// The password. + /// + public static SecureString ReadPassword(ConsoleColor? foreground, char? replaceChar, bool inline = false) + => StyleConsole.Default.ReadPassword(foreground, replaceChar, inline); + + /// + /// Moves cursor by a specific relative position. + /// + /// The horizontal translation size. + /// The vertical translation size. + public static void MoveCursorBy(int x, int y = 0) + => StyleConsole.Default.MoveCursorBy(x, y); + + /// + /// Moves cursor at a specific position in buffer. + /// + /// Column, the left from the edge of buffer. + /// Row, the top from the edge of buffer. + public static void MoveCursorTo(int x, int y) + => StyleConsole.Default.MoveCursorTo(x, y); + + /// + /// Removes the specific area. + /// + /// The area to remove. + public static void Clear(StyleConsole.RelativeAreas area) + => StyleConsole.Default.Clear(area); +} diff --git a/Console/CommandLine/HighlightConsoleStyle.cs b/Console/CommandLine/HighlightConsoleStyle.cs new file mode 100644 index 0000000..bdb5e36 --- /dev/null +++ b/Console/CommandLine/HighlightConsoleStyle.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +using Trivial.Collection; +using Trivial.Text; + +namespace Trivial.CommandLine; + +/// +/// The highlight console text style. +/// +public class HighlightConsoleStyle : IConsoleTextPrettier +{ + /// + /// Initialzies a new instance of the HighlightConsoleStyle class. + /// + /// The normal style. + /// The highlight style. + /// The query string. + public HighlightConsoleStyle(ConsoleTextStyle normal, ConsoleTextStyle highlight, IEnumerable q) + { + Normal = normal; + Highlight = highlight; + if (q != null) Query.AddRange(q.Where(ele => !string.IsNullOrEmpty(ele))); + } + + /// + /// Initialzies a new instance of the HighlightConsoleStyle class. + /// + /// The normal style. + /// The highlight style. + /// The query string. + /// One of the enumeration values that specifies the rules for the search. + public HighlightConsoleStyle(ConsoleTextStyle normal, ConsoleTextStyle highlight, string q, StringComparison? comparisonType = null) + { + Normal = normal; + Highlight = highlight; + if (!string.IsNullOrEmpty(q)) Query.Add(q); + if (comparisonType.HasValue) ComparisonType = comparisonType.Value; + } + + /// + /// Gets or sets the fallback foreground color. + /// + [JsonPropertyName("normal")] + public ConsoleTextStyle Normal { get; } = new(); + + /// + /// Gets or sets the fallback background color. + /// + [JsonPropertyName("highlight")] + public ConsoleTextStyle Highlight { get; } = new(); + + /// + /// Gets or sets a value indicating whether the text is strikeout. + /// + [JsonPropertyName("q")] + public List Query { get; } = new(); + + /// + /// Gets or sets one of the enumeration values that specifies the rules for the search. + /// + [JsonPropertyName("compare")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public StringComparison ComparisonType { get; set; } + + /// + /// The search starting position to search. + /// + [JsonPropertyName("start")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public int StartPosition { get; set; } + +#pragma warning disable IDE0057 + /// + /// Creates the console text collection based on this style. + /// + /// The text. + /// A collection of console text. + IEnumerable IConsoleTextPrettier.CreateTextCollection(string s) + { + var col = new List(); + var q = Query.Where(ele => !string.IsNullOrEmpty(ele)).ToList(); + var pos = StartPosition > 0 ? StartPosition : 0; + while (true) + { + if (pos >= s.Length) break; + var i = -1; + var hl = string.Empty; + foreach (var item in q) + { + var j = s.IndexOf(item, pos, ComparisonType); + if (j < 0 || (i >= 0 && j > i) || (i == j && item.Length < hl.Length)) continue; + i = j; + hl = item; + } + + if (i < 0) break; + col.Add(s.Substring(pos, i - pos), Normal); + col.Add(hl, Highlight); + pos += hl.Length; + } + + if (pos < s.Length) col.Add(s.Substring(pos), Normal); + return col; + } +#pragma warning restore IDE0057 +} diff --git a/Console/CommandLine/InfoRender.cs b/Console/CommandLine/InfoRender.cs new file mode 100644 index 0000000..746abfc --- /dev/null +++ b/Console/CommandLine/InfoRender.cs @@ -0,0 +1,360 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using System.Security; + +using Trivial.Text; + +namespace Trivial.CommandLine; + +/// +/// The extensions for console renderer. +/// +public static partial class ConsoleRenderExtensions +{ + /// + /// Writes an exception, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The exception. + /// true if output stack trace; otherwise, false. + public static void WriteLine(this StyleConsole cli, Exception ex, bool stackTrace = false) + => WriteLine(cli, new ConsoleTextStyle + { + ForegroundConsoleColor = ConsoleColor.Red + }, null, ex, stackTrace); + + /// + /// Writes an exception, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The style of header. + /// The style of details. + /// The exception. + /// true if output stack trace; otherwise, false. + public static void WriteLine(this StyleConsole cli, ConsoleTextStyle captionStyle, ConsoleTextStyle messageStyle, Exception ex, bool stackTrace = false) + { + if (ex == null) return; + cli ??= StyleConsole.Default; + var header = new ConsoleText(Resource.Error, captionStyle); + if (!string.IsNullOrWhiteSpace(ex.Message)) header.Content.Append(ex.Message); + var message = new ConsoleText(Environment.NewLine, messageStyle); + if (!string.IsNullOrWhiteSpace(ex.HelpLink)) + message.Content.AppendLine(ex.HelpLink); + message.Content.Append(ex.GetType().FullName); + if (ex.InnerException != null) + { + message.Content.Append($" > {ex.InnerException.GetType().FullName}"); + if (ex.InnerException is AggregateException aggEx && aggEx.InnerExceptions != null) + { + foreach (var iEx in aggEx.InnerExceptions) + { + message.Content.AppendLine(); + message.Content.Append($"- {iEx.GetType().FullName}\t{iEx.Message}"); + } + } + else + { + if (!string.IsNullOrWhiteSpace(ex.InnerException.Message)) + { + message.Content.AppendLine(); + message.Content.Append(ex.InnerException.Message); + } + } + } + + if (stackTrace && !string.IsNullOrWhiteSpace(ex.StackTrace)) + { + message.Content.AppendLine(); + message.Content.AppendLine("Stack trace"); + message.Content.Append(ex.StackTrace); + } + + cli.WriteLine(header, message); + } + /// + /// Writes an exception, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The error information. + public static void WriteLine(this StyleConsole cli, Data.ErrorMessageResult ex) + => WriteLine(cli, new ConsoleTextStyle + { + ForegroundConsoleColor = ConsoleColor.Red + }, null, ex); + + /// + /// Writes an exception, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The style of header. + /// The style of details. + /// The error information. + public static void WriteLine(this StyleConsole cli, ConsoleTextStyle captionStyle, ConsoleTextStyle messageStyle, Data.ErrorMessageResult ex) + { + if (ex == null) return; + cli ??= StyleConsole.Default; + var header = new ConsoleText(Resource.Error, captionStyle); + if (!string.IsNullOrWhiteSpace(ex.Message)) header.Content.Append(ex.Message); + var message = new ConsoleText(Environment.NewLine, messageStyle); + if (!string.IsNullOrWhiteSpace(ex.ErrorCode)) + message.Content.Append($" [ErrCode] {ex.ErrorCode}"); + if (ex.Details != null) + { + foreach (var line in ex.Details) + { + message.Content.AppendLine(); + message.Content.Append($"- {line}"); + } + } + + cli.WriteLine(header, message); + } + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The JSON instance. + public static void WriteLine(this StyleConsole cli, IJsonDataNode json) + => (cli ?? StyleConsole.Default).WriteLine(new JsonConsoleStyle().CreateTextCollection(json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The style. + /// The JSON instance. + public static void WriteLine(this StyleConsole cli, JsonConsoleStyle style, IJsonDataNode json) + => (cli ?? StyleConsole.Default).WriteLine((style ?? new JsonConsoleStyle()).CreateTextCollection(json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The JSON instance. + public static void WriteLine(this StyleConsole cli, System.Text.Json.Nodes.JsonObject json) + => (cli ?? StyleConsole.Default).WriteLine(new JsonConsoleStyle().CreateTextCollection(json == null ? null : (JsonObjectNode)json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The style. + /// The JSON instance. + public static void WriteLine(this StyleConsole cli, JsonConsoleStyle style, System.Text.Json.Nodes.JsonObject json) + => (cli ?? StyleConsole.Default).WriteLine((style ?? new JsonConsoleStyle()).CreateTextCollection(json == null ? null : (JsonObjectNode)json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The JSON instance. + public static void WriteLine(this StyleConsole cli, System.Text.Json.Nodes.JsonArray json) + => (cli ?? StyleConsole.Default).WriteLine(new JsonConsoleStyle().CreateTextCollection(json == null ? null : (JsonArrayNode)json, 0)); + + /// + /// Writes a JSON object, followed by the current line terminator, to the standard output stream. + /// It will flush immediately. + /// + /// The command line interface proxy. + /// The style. + /// The JSON instance. + public static void WriteLine(this StyleConsole cli, JsonConsoleStyle style, System.Text.Json.Nodes.JsonArray json) + => (cli ?? StyleConsole.Default).WriteLine((style ?? new JsonConsoleStyle()).CreateTextCollection(json == null ? null : (JsonArrayNode)json, 0)); + + /// + /// Adds an empty line. + /// + /// The console text collection. + public static void AddEmptyLine(this IList list) + => list?.Add(new ConsoleText(Environment.NewLine)); + + /// + /// Writes a sentense to allow pressing a key to continue. + /// + /// The command line interface proxy. + /// The style. + public static void PressAnyKeyToContinue(StyleConsole cli, ConsoleTextStyle style = null) + { + cli ??= StyleConsole.Default; + cli.WriteLine(style, Resource.PressAnyKeyToCont); + try + { + cli.ReadKey(true); + } + catch (InvalidOperationException) + { + } + catch (IOException) + { + } + catch (NotSupportedException) + { + } + + try + { + cli.ReadLine(); + } + catch (InvalidOperationException) + { + } + catch (IOException) + { + } + catch (NotSupportedException) + { + } + catch (ArgumentException) + { + } + + return; + } + + /// + /// Removes rest content value. + /// + /// The console text instance to limit length. + /// The length at most. + public static void RemoveRest(this ConsoleText s, int length) + { + if (s == null) return; + var sb = s.Content; + if (sb.Length <= length / 2) return; + var count = 0; + var n = new StringBuilder(); + foreach (var c in sb.ToString()) + { + var needStop = false; + switch (c) + { + case '\t': + count += 4; + break; + case '\r': + case '\n': + case '\0': + needStop = true; + break; + case '\b': + break; + default: + count += GetLetterWidth(c); + break; + } + + if (needStop || count > length) break; + n.Append(c); + } + + sb.Clear(); +#if NETFRAMEWORK + sb.Append(n.ToString()); +#else + sb.Append(n); +#endif + } + + /// + /// Tries to gets the row position of the cursor within the buffer area. + /// + /// The command line interface. + /// The row position of the cursor within the buffer area; or null if failed. + public static int? TryGetCursorTop(this StyleConsole cli) + { + try + { + return cli.CursorTop; + } + catch (IOException) + { + } + catch (InvalidOperationException) + { + } + catch (NotSupportedException) + { + } + catch (SecurityException) + { + } + + return null; + } + + /// + /// Tries to gets the column position of the cursor within the buffer area; or null if failed. + /// + /// The command line interface. + /// The column position of the cursor within the buffer area; or null if failed. + public static int? TryGetCursorLeft(this StyleConsole cli) + { + try + { + return (cli ?? StyleConsole.Default).CursorLeft; + } + catch (IOException) + { + } + catch (InvalidOperationException) + { + } + catch (NotSupportedException) + { + } + catch (SecurityException) + { + } + catch (System.Runtime.InteropServices.ExternalException) + { + } + catch (ArgumentException) + { + } + + return null; + } + + private static int GetBufferSafeWidth(StyleConsole cli) + { + try + { + return (cli ?? StyleConsole.Default).BufferWidth - 1; + } + catch (IOException) + { + } + catch (InvalidOperationException) + { + } + catch (NotSupportedException) + { + } + catch (SecurityException) + { + } + catch (System.Runtime.InteropServices.ExternalException) + { + } + catch (ArgumentException) + { + } + + return 70; + } +} diff --git a/Console/CommandLine/JsonConsoleStyle.cs b/Console/CommandLine/JsonConsoleStyle.cs new file mode 100644 index 0000000..dbc6ded --- /dev/null +++ b/Console/CommandLine/JsonConsoleStyle.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +using Trivial.Text; + +namespace Trivial.CommandLine; + +/// +/// The style for JSON output. +/// +public class JsonConsoleStyle : ICloneable +{ + /// + /// Gets or sets the foreground color of property key. + /// + [JsonPropertyName("property")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? PropertyForegroundRgbColor { get; set; } = Color.FromArgb(0xCE, 0x91, 0x78); + + /// + /// Gets or sets the foreground color of string value. + /// + [JsonPropertyName("string")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? StringForegroundRgbColor { get; set; } = Color.FromArgb(0xCE, 0x91, 0x78); + + /// + /// Gets or sets the foreground color of language keyword. + /// + [JsonPropertyName("keyword")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? KeywordForegroundRgbColor { get; set; } = Color.FromArgb(0x56, 0x9C, 0xD6); + + /// + /// Gets or sets the foreground color of number. + /// + [JsonPropertyName("number")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? NumberForegroundRgbColor { get; set; } = Color.FromArgb(0xB5, 0xCE, 0xA8); + + /// + /// Gets or sets the foreground color of punctuation. + /// + [JsonPropertyName("punctuation")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? PunctuationForegroundRgbColor { get; set; } = Color.FromArgb(0xDC, 0xDC, 0xDC); + + /// + /// Gets or sets the background color. + /// + [JsonPropertyName("back")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? BackgroundRgbColor { get; set; } + + /// + /// Gets or sets the foreground color of property key. + /// + [JsonPropertyName("property2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? PropertyForegroundConsoleColor { get; set; } = ConsoleColor.Gray; + + /// + /// Gets or sets the foreground color of string value. + /// + [JsonPropertyName("string2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? StringForegroundConsoleColor { get; set; } = ConsoleColor.Green; + + /// + /// Gets or sets the foreground color of keyword. + /// + [JsonPropertyName("keyword2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? KeywordForegroundConsoleColor { get; set; } = ConsoleColor.Cyan; + + /// + /// Gets or sets the foreground color of number. + /// + [JsonPropertyName("number2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? NumberForegroundConsoleColor { get; set; } = ConsoleColor.Yellow; + + /// + /// Gets or sets the foreground color of punctuation. + /// + [JsonPropertyName("punctuation2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? PunctuationForegroundConsoleColor { get; set; } = ConsoleColor.Gray; + + /// + /// Gets or sets the background color. + /// + [JsonPropertyName("back2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? BackgroundConsoleColor { get; set; } + + /// + /// Creates a console text by this style. + /// + /// The value. + /// A console text instance. + public ConsoleText CreateText(bool value) + => CreateByKeyword(value ? JsonBooleanNode.TrueString : JsonBooleanNode.FalseString); + + /// + /// Creates a console text by this style. + /// + /// The value. + /// A console text instance. + public ConsoleText CreateText(int value) + => new( + value.ToString("g"), + NumberForegroundRgbColor, + NumberForegroundConsoleColor, + BackgroundRgbColor, + BackgroundConsoleColor); + + /// + /// Creates a console text by this style. + /// + /// The value. + /// A console text instance. + public ConsoleText CreateText(string value) + { + return value == null ? CreateByKeyword(JsonValues.Null.ToString()) : new( + JsonStringNode.ToJson(value), + StringForegroundRgbColor, + StringForegroundConsoleColor, + BackgroundRgbColor, + BackgroundConsoleColor); + } + + /// + /// Clones an object. + /// + /// The object copied from this instance. + public virtual JsonConsoleStyle Clone() + => MemberwiseClone() as JsonConsoleStyle; + + /// + /// Clones an object. + /// + /// The object copied from this instance. + object ICloneable.Clone() + => MemberwiseClone(); + + /// + /// Creates a console text by this style. + /// + /// The JSON instance. + /// The current indent level. + /// A console text instance. + internal List CreateTextCollection(IJsonDataNode json, int indentLevel = 0) + { + var cmd = new List(); + if (json == null) + { + cmd.Add(CreateByKeyword(JsonValues.Null.ToString())); + return cmd; + } + + switch (json.ValueKind) + { + case JsonValueKind.Undefined: + case JsonValueKind.Null: + cmd.Add(CreateText(null)); + break; + case JsonValueKind.String: + cmd.Add(new(json.ToString(), + StringForegroundRgbColor, + StringForegroundConsoleColor, + BackgroundRgbColor, + BackgroundConsoleColor)); + break; + case JsonValueKind.Number: + cmd.Add(new(json.ToString(), + NumberForegroundRgbColor, + NumberForegroundConsoleColor, + BackgroundRgbColor, + BackgroundConsoleColor)); + break; + case JsonValueKind.True: + cmd.Add(CreateText(true)); + break; + case JsonValueKind.False: + cmd.Add(CreateText(false)); + break; + case JsonValueKind.Object: + cmd.AddRange(CreateTextCollection(json as JsonObjectNode, indentLevel)); + break; + case JsonValueKind.Array: + cmd.AddRange(CreateTextCollection(json as JsonArrayNode, indentLevel)); + break; + default: + break; + } + + return cmd; + } + + /// + /// Creates a console text by this style. + /// + /// The JSON instance. + /// The current indent level. + /// A console text instance. + private List CreateTextCollection(JsonObjectNode json, int indentLevel) + { + var cmd = new List(); + if (json == null) + { + cmd.Add(CreateByKeyword(JsonValues.Null.ToString())); + return cmd; + } + + var spaces = CreateByWhitespace(Environment.NewLine + new string(' ', (indentLevel + 1) * 2)); + cmd.Add(CreateByPunctuation("{")); + foreach (var prop in json) + { + cmd.Add(spaces); + cmd.Add(new( + JsonStringNode.ToJson(prop.Key), + PropertyForegroundRgbColor, + PropertyForegroundConsoleColor, + BackgroundRgbColor, + BackgroundConsoleColor)); + cmd.Add(CreateByPunctuation(": ")); + cmd.AddRange(CreateTextCollection(prop.Value, indentLevel + 1)); + cmd.Add(CreateByPunctuation(",")); + } + + if (cmd.Count > 1) cmd.RemoveAt(cmd.Count - 1); + cmd.Add(CreateByWhitespace(Environment.NewLine)); + cmd.Add(CreateByWhitespace(new string(' ', indentLevel * 2))); + cmd.Add(CreateByPunctuation("}")); + return cmd; + } + + /// + /// Creates a console text by this style. + /// + /// The JSON instance. + /// The current indent level. + /// A console text instance. + private List CreateTextCollection(JsonArrayNode json, int indentLevel) + { + var cmd = new List(); + if (json == null) + { + cmd.Add(CreateByKeyword(JsonValues.Null.ToString())); + return cmd; + } + + var spaces = CreateByWhitespace(Environment.NewLine + new string(' ', (indentLevel + 1) * 2)); + cmd.Add(CreateByPunctuation("[")); + foreach (var prop in json) + { + cmd.Add(spaces); + cmd.AddRange(CreateTextCollection(prop, indentLevel + 1)); + cmd.Add(CreateByPunctuation(",")); + } + + if (cmd.Count > 1) cmd.RemoveAt(cmd.Count - 1); + cmd.Add(CreateByWhitespace(Environment.NewLine)); + cmd.Add(CreateByWhitespace(new string(' ', indentLevel * 2))); + cmd.Add(CreateByPunctuation("]")); + return cmd; + } + + /// + /// Creates a console text by this style. + /// + /// The value. + /// A console text instance. + private ConsoleText CreateByKeyword(string value) + => new( + value, + KeywordForegroundRgbColor, + KeywordForegroundConsoleColor, + BackgroundRgbColor, + BackgroundConsoleColor); + + /// + /// Creates a console text by this style. + /// + /// The value. + /// A console text instance. + private ConsoleText CreateByPunctuation(string value) + => new( + value, + PunctuationForegroundRgbColor, + PunctuationForegroundConsoleColor, + BackgroundRgbColor, + BackgroundConsoleColor); + + /// + /// Creates a console text by this style. + /// + /// The value. + /// A console text instance. + private ConsoleText CreateByWhitespace(string value) + => new( + value, + null, + null, + BackgroundRgbColor, + BackgroundConsoleColor); +} diff --git a/Console/CommandLine/LinearGradientConsoleStyle.cs b/Console/CommandLine/LinearGradientConsoleStyle.cs new file mode 100644 index 0000000..e6960aa --- /dev/null +++ b/Console/CommandLine/LinearGradientConsoleStyle.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Trivial.Collection; +using Trivial.Text; + +namespace Trivial.CommandLine; + +/// +/// The linear gradient console text style. +/// +public class LinearGradientConsoleStyle : IConsoleTextPrettier +{ + private readonly Color? fromFore; + private readonly Color? toFore; + private readonly Color? fromBack; + private readonly Color? toBack; + + /// + /// Initialzies a new instance of the LinearGradientConsoleStyle class. + /// + /// The fallback foreground color. + /// The from foreground color. + /// The to foreground color. + public LinearGradientConsoleStyle(ConsoleColor? fallbackForegroundColor, Color fromForegroundColor, Color toForegroundColor) + { + FallbackForegroundColor = fallbackForegroundColor; + fromFore = fromForegroundColor; + toFore = toForegroundColor; + } + + /// + /// Initialzies a new instance of the LinearGradientConsoleStyle class. + /// + /// The fallback foreground color. + /// The from foreground color. + /// The to foreground color. + /// The fallback background color. + /// The from background color. + /// The to background color. + public LinearGradientConsoleStyle(ConsoleColor? fallbackForegroundColor, Color fromForegroundColor, Color toForegroundColor, ConsoleColor? fallbackBackgroundColor, Color fromBackgroundColor, Color toBackgroundColor) + : this(fallbackForegroundColor, fromForegroundColor, toForegroundColor) + { + FallbackBackgroundColor = fallbackBackgroundColor; + fromBack = fromBackgroundColor; + toBack = toBackgroundColor; + } + + /// + /// Gets or sets the fallback foreground color. + /// + public ConsoleColor? FallbackForegroundColor { get; set; } + + /// + /// Gets or sets the fallback background color. + /// + public ConsoleColor? FallbackBackgroundColor { get; set; } + + /// + /// Gets or sets a value indicating whether the text is blink. + /// + public bool Blink { get; set; } + + /// + /// Gets or sets a value indicating whether the text is bold. + /// + public bool Bold { get; set; } + + /// + /// Gets or sets a value indicating whether the text is italic. + /// + public bool Italic { get; set; } + + /// + /// Gets or sets a value indicating whether the text is underlined. + /// + public bool Underline { get; set; } + + /// + /// Gets or sets a value indicating whether the text is strikeout. + /// + public bool Strikeout { get; set; } + + /// + /// Creates the console text collection based on this style. + /// + /// The text. + /// A collection of console text. + IEnumerable IConsoleTextPrettier.CreateTextCollection(string s) + { + var col = new List(); + if (string.IsNullOrEmpty(s)) return col; + col.Add(s[0], 1, new ConsoleTextStyle(fromFore, FallbackForegroundColor, fromBack, FallbackBackgroundColor) + { + Blink = Blink, + Bold = Bold, + Italic = Italic, + Underline = Underline, + Strikeout = Strikeout + }); + if (s.Length == 1) + { + if (fromFore.HasValue && toFore.HasValue) + col[0].Style.ForegroundRgbColor = Color.FromArgb((fromFore.Value.R + toFore.Value.R) / 2, (fromFore.Value.G + toFore.Value.G) / 2, (fromFore.Value.B + toFore.Value.B) / 2); + else if (!fromFore.HasValue) + col[0].Style.ForegroundRgbColor = toFore; + if (fromBack.HasValue && toBack.HasValue) + col[0].Style.BackgroundRgbColor = Color.FromArgb((fromBack.Value.R + toBack.Value.R) / 2, (fromBack.Value.G + toBack.Value.G) / 2, (fromBack.Value.B + toBack.Value.B) / 2); + else if (!fromBack.HasValue) + col[0].Style.BackgroundRgbColor = toBack; + return col; + } + + var steps = s.Length - 1; + var hasFore = fromFore.HasValue || toFore.HasValue; + var hasBack = fromBack.HasValue || toBack.HasValue; + var foreDelta = fromFore.HasValue && toFore.HasValue + ? ((toFore.Value.R - fromFore.Value.R) * 1.0 / steps, (toFore.Value.G - fromFore.Value.B) * 1.0 / steps, (toFore.Value.B - fromFore.Value.B) * 1.0 / steps) + : (0.0, 0.0, 0.0); + var backDelta = fromBack.HasValue && toBack.HasValue + ? ((toBack.Value.R - fromBack.Value.R) * 1.0 / steps, (toBack.Value.G - fromBack.Value.B) * 1.0 / steps, (toBack.Value.B - fromBack.Value.B) * 1.0 / steps) + : (0.0, 0.0, 0.0); + double foreR = fromFore?.R ?? toFore?.R ?? 0; + double foreG = fromFore?.G ?? toFore?.G ?? 0; + double foreB = fromFore?.B ?? toFore?.B ?? 0; + double backR = fromBack?.R ?? toBack?.R ?? 0; + double backG = fromBack?.G ?? toBack?.G ?? 0; + double backB = fromBack?.B ?? toBack?.B ?? 0; + for (var i = 1; i < steps; i++) + { + Color? fore = hasFore ? Color.FromArgb( + PlusChannel(ref foreR, foreDelta.Item1), + PlusChannel(ref foreG, foreDelta.Item2), + PlusChannel(ref foreB, foreDelta.Item3)) : null; + Color? back = hasBack ? Color.FromArgb( + PlusChannel(ref backR, backDelta.Item1), + PlusChannel(ref backG, backDelta.Item2), + PlusChannel(ref backB, backDelta.Item3)) : null; + col.Add(s[i], 1, new ConsoleTextStyle(fore, FallbackForegroundColor, back, FallbackBackgroundColor) + { + Blink = Blink, + Bold = Bold, + Italic = Italic, + Underline = Underline, + Strikeout = Strikeout + }); + } + + col.Add(s[s.Length - 1], 1, new ConsoleTextStyle(toFore, FallbackForegroundColor, toBack, FallbackBackgroundColor) + { + Blink = Blink, + Bold = Bold, + Italic = Italic, + Underline = Underline, + Strikeout = Strikeout + }); + return col; + } + + private static int PlusChannel(ref double c, double delta) + { + c = Math.Round(c + delta); + var r = (int)c; + if (r < 0) return 0; + else if (r > 255) return 255; + return r; + } +} diff --git a/Console/CommandLine/ProgressRender.cs b/Console/CommandLine/ProgressRender.cs new file mode 100644 index 0000000..8f59a60 --- /dev/null +++ b/Console/CommandLine/ProgressRender.cs @@ -0,0 +1,222 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using System.Security; + +using Trivial.Collection; +using Trivial.Tasks; + +namespace Trivial.CommandLine; + +/// +/// The extensions for console renderer. +/// +public static partial class ConsoleRenderExtensions +{ + /// + /// Writes a progress component, followed by the current line terminator, to the standard output stream. + /// + /// The command line interface proxy. + /// The options. + /// The progress result. + public static OneProgress WriteLine(this StyleConsole cli, ConsoleProgressStyle style) + => WriteLine(cli, style, null); + + /// + /// Writes a progress component, followed by the current line terminator, to the standard output stream. + /// + /// The command line interface proxy. + /// The caption; or null if no caption. It will be better if it is less than 20 characters. + /// The progress size. + /// The progress kind. + /// The progress result. + public static OneProgress WriteLine(this StyleConsole cli, ConsoleProgressStyle.Sizes progressSize, string caption, ConsoleProgressStyle.Kinds kind = ConsoleProgressStyle.Kinds.Full) + => WriteLine(cli, progressSize != ConsoleProgressStyle.Sizes.None ? new ConsoleProgressStyle + { + Size = progressSize, + Kind = kind + } : null, caption); + + /// + /// Writes a progress component, followed by the current line terminator, to the standard output stream. + /// + /// The command line interface proxy. + /// The progress size. + /// The progress kind. + /// The progress result. + public static OneProgress WriteLine(this StyleConsole cli, ConsoleProgressStyle.Sizes progressSize, ConsoleProgressStyle.Kinds kind = ConsoleProgressStyle.Kinds.Full) + => WriteLine(cli, progressSize != ConsoleProgressStyle.Sizes.None ? new ConsoleProgressStyle + { + Size = progressSize, + Kind = kind + } : null, null); + + /// + /// Writes a progress component, followed by the current line terminator, to the standard output stream. + /// + /// The command line interface proxy. + /// The caption; or null if no caption. It will be better if it is less than 20 characters. + /// The style. + /// The progress result. + public static OneProgress WriteLine(this StyleConsole cli, ConsoleProgressStyle style, string caption) + { + if (cli == null) cli = StyleConsole.Default; + if (cli.Mode == StyleConsole.Modes.Text && cli.Handler == null) + { + var progress2 = new OneProgress(); + if (string.IsNullOrWhiteSpace(caption)) + { + cli.WriteLine(Resource.Loading); + progress2.ProgressChanged += (sender, ev) => + { + if (progress2.IsFailed || progress2.IsNotSupported) + cli.WriteLine($"{ev:#0%} {Resource.Error}"); + else if (progress2.IsCompleted) + cli.WriteLine($"√"); + }; + } + else + { + cli.WriteLine($"{caption} \t{Resource.Loading}"); + progress2.ProgressChanged += (sender, ev) => + { + if (progress2.IsFailed || progress2.IsNotSupported) + cli.WriteLine($"{caption} \t{ev:#0%} {Resource.Error}"); + else if (progress2.IsCompleted) + cli.WriteLine($"{caption} \t√"); + }; + } + + return progress2; + } + + if (style == null) style = new ConsoleProgressStyle(); + var status = RenderData(cli, style, caption, null, null); + var progress = new OneProgress(); + var top = TryGetCursorTop(cli) ?? -1; + progress.ProgressChanged += (sender, ev) => + { + var top2 = TryGetCursorTop(cli) ?? -1; + var left2 = TryGetCursorLeft(cli) ?? 0; + cli.Flush(); + if (cli.Mode == StyleConsole.Modes.Cmd && top >= 0 && top2 > top) + cli.MoveCursorBy(0, top - top2 - 1); + else + cli.MoveCursorBy(0, -1); + status = RenderData(cli, style, caption, progress, status); + if (cli.Mode == StyleConsole.Modes.Cmd && top >= 0 && top2 > top) + cli.MoveCursorTo(left2, top2); + }; + return progress; + } + + private static string RenderData(StyleConsole cli, ConsoleProgressStyle style, string caption, OneProgress value, string status) + { + var maxWidth = GetBufferSafeWidth(cli); + var width = style.Size switch + { + ConsoleProgressStyle.Sizes.None => 0, + ConsoleProgressStyle.Sizes.Short => maxWidth > 70 ? 20 : 10, + ConsoleProgressStyle.Sizes.Wide => maxWidth > 88 ? 60 : 40, + ConsoleProgressStyle.Sizes.Full => maxWidth - 5, + _ => maxWidth > 70 ? (maxWidth > 88 ? 40 : 30) : 20 + }; + var barChar = style.Kind switch + { + ConsoleProgressStyle.Kinds.AngleBracket => '>', + ConsoleProgressStyle.Kinds.Plus => '+', + ConsoleProgressStyle.Kinds.Sharp => '#', + ConsoleProgressStyle.Kinds.X => 'x', + ConsoleProgressStyle.Kinds.O => 'o', + _ => ' ', + }; + var pendingChar = style.Kind switch + { + ConsoleProgressStyle.Kinds.AngleBracket => '=', + ConsoleProgressStyle.Kinds.Plus => '-', + ConsoleProgressStyle.Kinds.Sharp => '-', + ConsoleProgressStyle.Kinds.X => '.', + ConsoleProgressStyle.Kinds.O => '.', + _ => ' ', + }; + var col = new List(); + if (!string.IsNullOrWhiteSpace(caption)) + { + var sb = new StringBuilder(); + var j = style.IgnoreCaptionSeparator ? 0 : 1; + foreach (var c in caption) + { + var c2 = c; + switch (c) + { + case '\t': + case '\r': + case '\n': + j++; + c2 = ' '; + break; + case '\0': + case '\b': + continue; + default: + j += GetLetterWidth(c); + break; + } + + sb.Append(c2); + } + + if (!style.IgnoreCaptionSeparator) sb.Append(' '); + col.Add(sb, new ConsoleTextStyle(style.CaptionRgbColor, style.CaptionConsoleColor, style.BackgroundRgbColor, style.BackgroundConsoleColor)); + if (style.Size == ConsoleProgressStyle.Sizes.Full) + width -= j; + } + + var v = value?.Value ?? -1; + if (v > 1) v = 1; + if (double.IsNaN(v)) + { + cli.WriteLine(col); + return null; + } + + var w = (int)Math.Round(width * v); + if (w < 0) w = 0; + var isError = value?.IsFailed == true || value?.IsNotSupported == true; + var isSucc = !isError && value?.IsSuccessful == true; + var newStatus = $"{(isError ? "e" : (isSucc ? "s" : "p"))}{w}/{maxWidth}"; + if (status == newStatus) + { + cli.Flush(); + cli.MoveCursorBy(0, 1); + return status; + } + + if (barChar == ' ') + { + col.Add(barChar, w, new ConsoleTextStyle(null, null, isError ? style.ErrorRgbColor : style.BarRgbColor, isError ? style.ErrorConsoleColor : style.BarConsoleColor)); + col.Add(pendingChar, width - w, new ConsoleTextStyle(null, null, style.PendingRgbColor, style.PendingConsoleColor)); + } + else + { + col.Add(barChar, w, new ConsoleTextStyle(isError ? style.ErrorRgbColor : style.BarRgbColor, isError ? style.ErrorConsoleColor : style.BarConsoleColor, style.BackgroundRgbColor, style.BackgroundConsoleColor)); + col.Add(pendingChar, width - w, new ConsoleTextStyle(style.PendingRgbColor, style.PendingConsoleColor, style.BackgroundRgbColor, style.BackgroundConsoleColor)); + } + + if (v >= 0) + { + var s = v.ToString("#0%"); + if (s.Length > 3) s = isSucc ? " √" : "99%"; + col.Add(" " + s, new ConsoleTextStyle(style.ValueRgbColor, style.ValueConsoleColor, style.BackgroundRgbColor, style.BackgroundConsoleColor)); + } + + cli.Flush(); + cli.Clear(StyleConsole.RelativeAreas.Line); + cli.BackspaceToBeginning(); + cli.WriteLine(col); + return status; + } +} diff --git a/Console/CommandLine/ProgressStyle.cs b/Console/CommandLine/ProgressStyle.cs new file mode 100644 index 0000000..1586a73 --- /dev/null +++ b/Console/CommandLine/ProgressStyle.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +using Trivial.Text; + +namespace Trivial.CommandLine; + +/// +/// The style of progress line console component. +/// +public class ConsoleProgressStyle +{ + /// + /// Progress sizes (width). + /// + public enum Sizes : byte + { + /// + /// Normal size. + /// + Normal = 0, + + /// + /// Short size. + /// + Short = 1, + + /// + /// Wide size. + /// + Wide = 2, + + /// + /// The progress and its related text will stretch horizontal in the console. + /// + Full = 3, + + /// + /// No progress bar but only a value. + /// + None = 4 + } + + /// + /// The output text kinds filling in progress. + /// + public enum Kinds : byte + { + /// + /// Whitespace (rectangle). + /// + Full = 0, + + /// + /// Left angle bracket (less sign). + /// + AngleBracket = 1, + + /// + /// Plus sign. + /// + Plus = 2, + + /// + /// Sharp. + /// + Sharp = 3, + + /// + /// Character x. + /// + X = 4, + + /// + /// Character o. + /// + O = 5 + } + + /// + /// Gets or sets the background color of the component. + /// + [JsonPropertyName("back2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? BackgroundConsoleColor { get; set; } + + /// + /// Gets or sets the background color of the component. + /// + [JsonPropertyName("back")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? BackgroundRgbColor { get; set; } + + /// + /// Gets or sets the progress background color. + /// + [JsonPropertyName("pending2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + public ConsoleColor PendingConsoleColor { get; set; } = ConsoleColor.DarkGray; + + /// + /// Gets or sets the progress background color. + /// + [JsonPropertyName("pending")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? PendingRgbColor { get; set; } = Color.FromArgb(68, 68, 68); + + /// + /// Gets or sets the progress bar color. + /// + [JsonPropertyName("bar2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + public ConsoleColor BarConsoleColor { get; set; } = ConsoleColor.Green; + + /// + /// Gets or sets the progress bar color. + /// + [JsonPropertyName("bar")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? BarRgbColor { get; set; } = Color.FromArgb(48, 192, 128); + + /// + /// Gets or sets the error color. + /// + [JsonPropertyName("error2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + public ConsoleColor ErrorConsoleColor { get; set; } = ConsoleColor.Red; + + /// + /// Gets or sets the error color. + /// + [JsonPropertyName("error")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? ErrorRgbColor { get; set; } = Color.FromArgb(212, 48, 48); + + /// + /// Gets or sets the foreground color of caption. + /// + [JsonPropertyName("caption2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? CaptionConsoleColor { get; set; } + + /// + /// Gets or sets the foreground color of caption. + /// + [JsonPropertyName("caption")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? CaptionRgbColor { get; set; } + + /// + /// Gets or sets the foreground color of value. + /// + [JsonPropertyName("value2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? ValueConsoleColor { get; set; } = ConsoleColor.Gray; + + /// + /// Gets or sets the foreground color of value. + /// + [JsonPropertyName("value")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? ValueRgbColor { get; set; } + + /// + /// Gets or sets the progress size (width). + /// + [JsonPropertyName("size")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + public Sizes Size { get; set; } + + /// + /// Gets or sets the progress style. + /// + [JsonPropertyName("kind")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + public Kinds Kind { get; set; } + + /// + /// Gets or sets a value indicating whether remove the white space between caption and progress. + /// + [JsonPropertyName("slim")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool IgnoreCaptionSeparator { get; set; } +} diff --git a/Console/CommandLine/RepeatedColorConsoleStyle.cs b/Console/CommandLine/RepeatedColorConsoleStyle.cs new file mode 100644 index 0000000..ec30ddc --- /dev/null +++ b/Console/CommandLine/RepeatedColorConsoleStyle.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Trivial.Collection; +using Trivial.Text; + +namespace Trivial.CommandLine; + +/// +/// The linear gradient console text style. +/// +public class RepeatedColorConsoleStyle : IConsoleTextPrettier +{ + /// + /// Initialzies a new instance of the RepeatedColorConsoleStyle class. + /// + public RepeatedColorConsoleStyle() + { + } + + /// + /// Initialzies a new instance of the RepeatedColorConsoleStyle class. + /// + /// The fallback foreground color. + /// The foreground colors. + public RepeatedColorConsoleStyle(ConsoleColor fallbackForegroundColor, IEnumerable foregroundColors) + { + ForegroundConsoleColors.Add(fallbackForegroundColor); + if (foregroundColors != null) ForegroundRgbColors.AddRange(foregroundColors); + } + + /// + /// Initialzies a new instance of the RepeatedColorConsoleStyle class. + /// + /// The foreground console colors. + /// The foreground RGB colors. + public RepeatedColorConsoleStyle(IEnumerable foregroundConsoleColors, IEnumerable foregroundRgbColors) + { + if (foregroundConsoleColors != null) ForegroundConsoleColors.AddRange(foregroundConsoleColors); + if (foregroundRgbColors != null) ForegroundRgbColors.AddRange(foregroundRgbColors); + } + + /// + /// Initialzies a new instance of the RepeatedColorConsoleStyle class. + /// + /// The foreground console colors. + /// The foreground RGB colors. + /// The background console colors. + /// The background RGB colors. + public RepeatedColorConsoleStyle(IEnumerable foregroundConsoleColors, IEnumerable foregroundRgbColors, ConsoleColor? backgroundConsoleColor, Color? backgroundRgbColor) + { + if (foregroundConsoleColors != null) ForegroundConsoleColors.AddRange(foregroundConsoleColors); + if (foregroundRgbColors != null) ForegroundRgbColors.AddRange(foregroundRgbColors); + if (backgroundConsoleColor.HasValue) BackgroundConsoleColors.Add(backgroundConsoleColor.Value); + if (backgroundRgbColor.HasValue) BackgroundRgbColors.Add(backgroundRgbColor.Value); + } + + /// + /// Initialzies a new instance of the RepeatedColorConsoleStyle class. + /// + /// The foreground console colors. + /// The foreground RGB colors. + /// The background console colors. + /// The background RGB colors. + public RepeatedColorConsoleStyle(IEnumerable foregroundConsoleColors, IEnumerable foregroundRgbColors, IEnumerable backgroundConsoleColors, IEnumerable backgroundRgbColors) + { + if (foregroundConsoleColors != null) ForegroundConsoleColors.AddRange(foregroundConsoleColors); + if (foregroundRgbColors != null) ForegroundRgbColors.AddRange(foregroundRgbColors); + if (backgroundConsoleColors != null) BackgroundConsoleColors.AddRange(backgroundConsoleColors); + if (backgroundRgbColors != null) BackgroundRgbColors.AddRange(backgroundRgbColors); + } + + /// + /// Initialzies a new instance of the RepeatedColorConsoleStyle class. + /// + /// The foreground console color. + /// The foreground RGB color. + /// The background console colors. + /// The background RGB colors. + public RepeatedColorConsoleStyle(ConsoleColor foregroundConsoleColor, Color foregroundRgbColor, IEnumerable backgroundConsoleColors, IEnumerable backgroundRgbColors) + { + ForegroundConsoleColors.Add(foregroundConsoleColor); + ForegroundRgbColors.Add(foregroundRgbColor); + if (backgroundConsoleColors != null) BackgroundConsoleColors.AddRange(backgroundConsoleColors); + if (backgroundRgbColors != null) BackgroundRgbColors.AddRange(backgroundRgbColors); + } + + /// + /// Gets or sets the foreground console colors. + /// + public List ForegroundConsoleColors { get; } = new(); + + /// + /// Gets or sets the foreground RGB colors. + /// + public List ForegroundRgbColors { get; } = new(); + + /// + /// Gets or sets the background console colors. + /// + public List BackgroundConsoleColors { get; } = new(); + + /// + /// Gets or sets the background RGB colors. + /// + public List BackgroundRgbColors { get; } = new(); + + /// + /// Gets or sets a value indicating whether the text is blink. + /// + public bool Blink { get; set; } + + /// + /// Gets or sets a value indicating whether the text is bold. + /// + public bool Bold { get; set; } + + /// + /// Gets or sets a value indicating whether the text is italic. + /// + public bool Italic { get; set; } + + /// + /// Gets or sets a value indicating whether the text is underlined. + /// + public bool Underline { get; set; } + + /// + /// Gets or sets a value indicating whether the text is strikeout. + /// + public bool Strikeout { get; set; } + + /// + /// Creates the console text collection based on this style. + /// + /// The text. + /// A collection of console text. + IEnumerable IConsoleTextPrettier.CreateTextCollection(string s) + { + var col = new List(); + if (string.IsNullOrEmpty(s)) return col; + if (ForegroundConsoleColors.Count < 2 && ForegroundRgbColors.Count < 2 && BackgroundConsoleColors.Count < 2 && BackgroundRgbColors.Count < 2) + { + col.Add(s, new ConsoleTextStyle( + ForegroundRgbColors.FirstOrDefault(), + ForegroundConsoleColors.FirstOrDefault(), + BackgroundRgbColors.FirstOrDefault(), + BackgroundConsoleColors.FirstOrDefault()) + { + Blink = Blink, + Bold = Bold, + Italic = Italic, + Underline = Underline, + Strikeout = Strikeout + }); + return col; + } + + var i = 0; + foreach (var c in s) + { + Color? foreRgb = ForegroundRgbColors.Count > 0 + ? ForegroundRgbColors[i % ForegroundRgbColors.Count] + : null; + ConsoleColor? foreConsole = ForegroundConsoleColors.Count > 0 + ? ForegroundConsoleColors[i % ForegroundConsoleColors.Count] + : null; + Color? backRgb = BackgroundRgbColors.Count > 0 + ? BackgroundRgbColors[i % BackgroundRgbColors.Count] + : null; + ConsoleColor? backConsole = BackgroundConsoleColors.Count > 0 + ? BackgroundConsoleColors[i % BackgroundConsoleColors.Count] + : null; + i++; + col.Add(c, 1, new ConsoleTextStyle(foreRgb, foreConsole, backRgb, backConsole) + { + Blink = Blink, + Bold = Bold, + Italic = Italic, + Underline = Underline, + Strikeout = Strikeout + }); + } + + return col; + } +} diff --git a/Console/CommandLine/Resource.Designer.cs b/Console/CommandLine/Resource.Designer.cs new file mode 100644 index 0000000..ef0a6fc --- /dev/null +++ b/Console/CommandLine/Resource.Designer.cs @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Trivial.CommandLine { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Trivial.CommandLine.Resource", typeof(Resource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 End the current conversation. 的本地化字符串。 + /// + internal static string EndConversation { + get { + return ResourceManager.GetString("EndConversation", resourceCulture); + } + } + + /// + /// 查找类似 Error! 的本地化字符串。 + /// + internal static string Error { + get { + return ResourceManager.GetString("Error", resourceCulture); + } + } + + /// + /// 查找类似 Get help. 的本地化字符串。 + /// + internal static string GetHelp { + get { + return ResourceManager.GetString("GetHelp", resourceCulture); + } + } + + /// + /// 查找类似 Loading... 的本地化字符串。 + /// + internal static string Loading { + get { + return ResourceManager.GetString("Loading", resourceCulture); + } + } + + /// + /// 查找类似 Press any key to continue... 的本地化字符串。 + /// + internal static string PressAnyKeyToCont { + get { + return ResourceManager.GetString("PressAnyKeyToCont", resourceCulture); + } + } + + /// + /// 查找类似 Tips: [↑][↓][←][→] Select; [ENTER] OK. 的本地化字符串。 + /// + internal static string SelectionTips { + get { + return ResourceManager.GetString("SelectionTips", resourceCulture); + } + } + + /// + /// 查找类似 Select: 的本地化字符串。 + /// + internal static string ToSelect { + get { + return ResourceManager.GetString("ToSelect", resourceCulture); + } + } + } +} diff --git a/Console/CommandLine/Resource.de.resx b/Console/CommandLine/Resource.de.resx new file mode 100644 index 0000000..f57cd5a --- /dev/null +++ b/Console/CommandLine/Resource.de.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Beenden Sie die aktuelle Sitzung. + + + Fehler! + + + Holen Sie sich Hilfe. + + + Laden... + + + Drücken Sie eine beliebige Taste, um fortzufahren... + + + Tipps: [↑][↓][←][→] Wählen; [ENTER] OKAY. + + + Wählen: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.en.resx b/Console/CommandLine/Resource.en.resx new file mode 100644 index 0000000..1a42488 --- /dev/null +++ b/Console/CommandLine/Resource.en.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + End the current conversation. + + + Error! + + + Get help. + + + Loading... + + + Press any key to continue... + + + Tips: [↑][↓][←][→] Select; [ENTER] OK. + + + Select: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.es.resx b/Console/CommandLine/Resource.es.resx new file mode 100644 index 0000000..bb3cec0 --- /dev/null +++ b/Console/CommandLine/Resource.es.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Termine la conversación actual. + + + Error! + + + Ayuda. + + + Cargando... + + + Pulsa cualquier tecla para continuar... + + + Tips: [↑][↓][←][→] Seleccione; [ENTER] OK. + + + Seleccione: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.fr.resx b/Console/CommandLine/Resource.fr.resx new file mode 100644 index 0000000..1d914f8 --- /dev/null +++ b/Console/CommandLine/Resource.fr.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Mettez fin à la conversation en cours. + + + Erreur! + + + Obtenez de l’aide. + + + Chargement... + + + Appuyez sur n’importe quelle touche pour continuer... + + + Conseils: [↑][↓][←][→]=Sélectionnez; [ENTRÉE]=D’accord. + + + Choisir: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.ja.resx b/Console/CommandLine/Resource.ja.resx new file mode 100644 index 0000000..4bc2539 --- /dev/null +++ b/Console/CommandLine/Resource.ja.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 会話の終了。 + + + エラー! + + + 情報を取得します。 + + + 読み込み中…… + + + 任意のキーを押して続行します…… + + + 操作提示:[↑][↓][←][→]=選択;[ENTER]=確定。 + + + 選択してください: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.ko.resx b/Console/CommandLine/Resource.ko.resx new file mode 100644 index 0000000..9b827c7 --- /dev/null +++ b/Console/CommandLine/Resource.ko.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 현재 대화를 종료합니다. + + + 오류! + + + 정보를 가져옵니다. + + + 로드... + + + 계속하려면 키를 누릅니다. + + + 팁: [↑][↓][←][→]=선택;[ENTER]=오케이. + + + 선택: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.pt.resx b/Console/CommandLine/Resource.pt.resx new file mode 100644 index 0000000..760ee1c --- /dev/null +++ b/Console/CommandLine/Resource.pt.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Termine a conversa atual. + + + Erro! + + + Pedir ajuda. + + + Carregamento... + + + Pressione qualquer tecla para continuar... + + + Dicas: [↑][↓][←][→] Selecione; [ENTER] OK. + + + Selecione: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.resx b/Console/CommandLine/Resource.resx new file mode 100644 index 0000000..1a42488 --- /dev/null +++ b/Console/CommandLine/Resource.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + End the current conversation. + + + Error! + + + Get help. + + + Loading... + + + Press any key to continue... + + + Tips: [↑][↓][←][→] Select; [ENTER] OK. + + + Select: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.ru.resx b/Console/CommandLine/Resource.ru.resx new file mode 100644 index 0000000..a75dd63 --- /dev/null +++ b/Console/CommandLine/Resource.ru.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Завершите текущую беседу. + + + Ошибка! + + + Справка. + + + Погрузка... + + + Нажмите любую клавишу, чтобы продолжить... + + + Советы: [↑][↓][←][→] Выбирать; [ENTER] Ок. + + + Выбирать: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.zh-Hans.resx b/Console/CommandLine/Resource.zh-Hans.resx new file mode 100644 index 0000000..78d5995 --- /dev/null +++ b/Console/CommandLine/Resource.zh-Hans.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 退出当前会话。 + + + 错误! + + + 获取帮助。 + + + 加载中…… + + + 按任意键继续…… + + + 请先按方向键进行选择,然后按回车键确定。 + + + 请选择: + + \ No newline at end of file diff --git a/Console/CommandLine/Resource.zh-Hant.resx b/Console/CommandLine/Resource.zh-Hant.resx new file mode 100644 index 0000000..92909c0 --- /dev/null +++ b/Console/CommandLine/Resource.zh-Hant.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 退出當前會話。 + + + 錯誤! + + + 獲取説明。 + + + 載入中…… + + + 按任意鍵繼續...... + + + 操作提示:[↑][↓][←][→]=選擇;[ENTER]=確定。 + + + 請選擇: + + \ No newline at end of file diff --git a/Console/CommandLine/SelectionOptions.cs b/Console/CommandLine/SelectionOptions.cs new file mode 100644 index 0000000..730e7d5 --- /dev/null +++ b/Console/CommandLine/SelectionOptions.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +using Trivial.Text; + +namespace Trivial.CommandLine; + +/// +/// The selection options. +/// +public class SelectionConsoleOptions : ICloneable +{ + /// + /// Gets or sets the minimum length for each item. + /// + [JsonPropertyName("minlen")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? MinLength { get; set; } + + /// + /// Gets or sets the maximum length for each item. + /// + [JsonPropertyName("maxlen")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? MaxLength { get; set; } + + /// + /// Gets or sets the maximum column count to display. + /// + [JsonPropertyName("columns")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? Column { get; set; } + + /// + /// Gets or sets maximum row count per page. + /// null for disable paging. + /// + [JsonPropertyName("rows")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? MaxRow { get; set; } + + /// + /// Gets or sets the tips. + /// null for disable tips. + /// + [JsonPropertyName("tip")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Tips { get; set; } = Resource.SelectionTips; + + /// + /// Gets or sets the paging tips. + /// Or null to disable tips. + /// + [JsonPropertyName("pagetip")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string PagingTips { get; set; } = "← [PgUp] | {from} - {end} / {total} | [PgDn] →"; + + /// + /// Gets or sets the question message for keyboard selecting. + /// Or null to disable additional question line. + /// + [JsonPropertyName("q")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Question { get; set; } = Resource.ToSelect; + + /// + /// Gets or sets the question message for manual typing. + /// Or null to disable manual mode. + /// + [JsonPropertyName("manualq")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string ManualQuestion { get; set; } + + /// + /// Gets or sets the question message displayed when it is not supported. + /// Or null to disable manual mode. + /// + [JsonPropertyName("notsupportq")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string QuestionWhenNotSupported { get; set; } + + /// + /// Gets or sets the foreground color for item. + /// + [JsonPropertyName("fore")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? ForegroundColor { get; set; } + + /// + /// Gets or sets the background color for item. + /// + [JsonPropertyName("back")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? BackgroundColor { get; set; } + + /// + /// Gets or sets the foreground color for item selected. + /// + [JsonPropertyName("selfore2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? SelectedForegroundConsoleColor { get; set; } = ConsoleColor.Black; + + /// + /// Gets or sets the foreground color for item selected. + /// + [JsonPropertyName("selfore")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? SelectedForegroundRgbColor { get; set; } + + /// + /// Gets or sets the foreground color for item selected. + /// + [JsonPropertyName("selback2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? SelectedBackgroundConsoleColor { get; set; } = ConsoleColor.Cyan; + + /// + /// Gets or sets the foreground color for item selected. + /// + [JsonPropertyName("selback")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? SelectedBackgroundRgbColor { get; set; } = Color.FromArgb(0x55, 0xCC, 0xEE); + + /// + /// Gets or sets the foreground color for question. + /// + [JsonPropertyName("qfore2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? QuestionForegroundConsoleColor { get; set; } + + /// + /// Gets or sets the foreground color for question. + /// + [JsonPropertyName("qfore")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? QuestionForegroundRgbColor { get; set; } + + /// + /// Gets or sets the background color for question. + /// + [JsonPropertyName("qback2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? QuestionBackgroundConsoleColor { get; set; } + + /// + /// Gets or sets the background color for question. + /// + [JsonPropertyName("qback")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? QuestionBackgroundRgbColor { get; set; } + + /// + /// Gets or sets the foreground color for tips. + /// + [JsonPropertyName("tipfore2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? TipsForegroundConsoleColor { get; set; } = ConsoleColor.Yellow; + + /// + /// Gets or sets the foreground color for tips. + /// + [JsonPropertyName("tipfore")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? TipsForegroundRgbColor { get; set; } = Color.FromArgb(0xF9, 0xEE, 0x88); + + /// + /// Gets or sets the background color for tips. + /// + [JsonPropertyName("tipback2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? TipsBackgroundConsoleColor { get; set; } + + /// + /// Gets or sets the background color for tips. + /// + [JsonPropertyName("tipback")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? TipsBackgroundRgbColor { get; set; } + + /// + /// Gets or sets the foreground color for paing tips. + /// + [JsonPropertyName("pagefore2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? PagingForegroundConsoleColor { get; set; } + + /// + /// Gets or sets the foreground color for paing tips. + /// + [JsonPropertyName("pagefore")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? PagingForegroundRgbColor { get; set; } + + /// + /// Gets or sets the background color for paging tips. + /// + [JsonPropertyName("pageback2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? PagingBackgroundConsoleColor { get; set; } + + /// + /// Gets or sets the background color for paging tips. + /// + [JsonPropertyName("pageback")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? PagingBackgroundRgbColor { get; set; } + + /// + /// Gets or sets the foreground color for default value. + /// + [JsonPropertyName("itemfore2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? ItemForegroundConsoleColor { get; set; } + + /// + /// Gets or sets the foreground color for default value. + /// + [JsonPropertyName("itemfore")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? ItemForegroundRgbColor { get; set; } + + /// + /// Gets or sets the background color for default value. + /// + [JsonPropertyName("itemback2")] + [JsonConverter(typeof(JsonIntegerEnumCompatibleConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ConsoleColor? ItemBackgroundConsoleColor { get; set; } + + /// + /// Gets or sets the background color for default value. + /// + [JsonPropertyName("itemback")] + [JsonConverter(typeof(JsonNumberConverter))] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Color? ItemBackgroundRgbColor { get; set; } + + /// + /// Gets or sets the prefix for the item. + /// + [JsonPropertyName("prefix")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string Prefix { get; set; } + + /// + /// Gets or sets the prefix for the item selected. + /// + [JsonPropertyName("selprefix")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string SelectedPrefix { get; set; } + + /// + /// Clones an object. + /// + /// The object copied from this instance. + public virtual SelectionConsoleOptions Clone() + => MemberwiseClone() as SelectionConsoleOptions; + + /// + /// Clones an object. + /// + /// The object copied from this instance. + object ICloneable.Clone() + => MemberwiseClone(); +} diff --git a/Console/CommandLine/SelectionRender.cs b/Console/CommandLine/SelectionRender.cs new file mode 100644 index 0000000..38336d5 --- /dev/null +++ b/Console/CommandLine/SelectionRender.cs @@ -0,0 +1,867 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using System.Security; + +using Trivial.Collection; + +namespace Trivial.CommandLine; + +/// +/// The extensions for console renderer. +/// +public static partial class ConsoleRenderExtensions +{ + /// + /// Writes a collection of item for selecting. + /// + /// The command line interface proxy. + /// The collection data. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(this StyleConsole cli, SelectionData collection, SelectionConsoleOptions options = null) + => Select(cli, collection, options); + + /// + /// Writes a collection of item for selecting. + /// + /// The command line interface proxy. + /// The collection data. + /// The converter. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(this StyleConsole cli, IEnumerable collection, Func> convert, SelectionConsoleOptions options = null) + { + var c = new SelectionData(); + c.AddRange(collection.Select(convert)); + return Select(cli, c, options); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The command line interface proxy. + /// The collection data. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(this StyleConsole cli, IEnumerable> collection, SelectionConsoleOptions options = null) + { + var c = new SelectionData(); + c.AddRange(collection); + return Select(cli, c, options); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The command line interface proxy. + /// The parent foler path. + /// The selection display options. + /// The search string to match against the names of directories and files. This parameter can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn't support regular expressions. + /// The result of selection. + /// searchPattern contains one or more invalid characters defined by the System.IO.Path.GetInvalidPathChars method. + /// The specified path is invalid (for example, it is on an unmapped drive). + /// The caller does not have the required permission. + public static SelectionResult Select(this StyleConsole cli, DirectoryInfo path, SelectionConsoleOptions options = null, string searchPattern = null) + { + var c = new SelectionData(); + var col = string.IsNullOrEmpty(searchPattern) ? path.GetFileSystemInfos() : path.GetFileSystemInfos(searchPattern); + foreach (var f in col) + { + c.Add(f.Name, f); + } + + return Select(cli, c, options); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The command line interface proxy. + /// The parent foler path. + /// true if only display files; otherwise, false. + /// The selection display options. + /// The search string to match against the names of directories and files. This parameter can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn't support regular expressions. + /// The result of selection. + /// searchPattern contains one or more invalid characters defined by the System.IO.Path.GetInvalidPathChars method. + /// The specified path is invalid (for example, it is on an unmapped drive). + /// The caller does not have the required permission. + public static SelectionResult Select(this StyleConsole cli, DirectoryInfo path, bool onlyFiles, SelectionConsoleOptions options = null, string searchPattern = null) + { + if (!onlyFiles) return Select(cli, path, options, searchPattern); + var c = new SelectionData(); + var col = string.IsNullOrEmpty(searchPattern) ? path.GetFiles() : path.GetFiles(searchPattern); + foreach (var f in col) + { + c.Add(f.Name, f); + } + + return Select(cli, c, options); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The command line interface proxy. + /// The parent foler path. + /// A function to test each element for a condition. + /// The selection display options. + /// The result of selection. + /// The specified path is invalid (for example, it is on an unmapped drive). + /// The caller does not have the required permission. + public static SelectionResult Select(this StyleConsole cli, DirectoryInfo path, Func predicate, SelectionConsoleOptions options = null) + { + var c = new SelectionData(); + IEnumerable col = path.GetFileSystemInfos(); + if (predicate != null) col = col.Where(predicate); + foreach (var f in col) + { + c.Add(f.Name, f); + } + + return Select(cli, c, options); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The type of data. + /// The command line interface proxy. + /// The collection data. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(this StyleConsole cli, SelectionData collection, SelectionConsoleOptions options = null) + { + if (collection == null) return null; + if (cli == null) cli = StyleConsole.Default; + if (options == null) options = new(); + else options = options.Clone(); + cli.Flush(); + if (cli.Handler == null && cli.Mode == StyleConsole.Modes.Text) + return SelectForText(cli, collection, options); + return Select(cli, collection, options, 0); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The command line interface proxy. + /// The collection data. + /// The selection display options. + /// The result of selection. + public static SelectionResult Select(this StyleConsole cli, IEnumerable collection, SelectionConsoleOptions options = null) + { + if (collection == null) return null; + if (cli == null) cli = StyleConsole.Default; + if (options == null) options = new(); + else options = options.Clone(); + cli.Flush(); + var c = new SelectionData(); + c.AddRange(collection); + if (cli.Handler == null && cli.Mode == StyleConsole.Modes.Text) + return SelectForText(cli, c, options); + return Select(cli, c, options, 0); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The type of data. + /// The command line interface proxy. + /// The collection data. + /// The selection display options. + /// The index of item selected. + /// The result of selection. + private static SelectionResult Select(StyleConsole cli, SelectionData collection, SelectionConsoleOptions options, int select) + { + var temp = (0, 0, 0, 0, false, false, 0, 0); + var oldSelect = select; + while (true) + { + var list = collection.ToList(); + void resetSelect() + { + if (oldSelect < 0 || oldSelect >= list.Count) return; + var h = temp.Item3 + (temp.Item5 ? 2 : 1) + (temp.Item6 ? 1 : 0); + var oldItem = list[oldSelect]; + var y2 = Math.DivRem(oldSelect % temp.Item7, temp.Item4, out var x2) - h; + x2 *= temp.Item8; + cli.MoveCursorBy(x2, y2); + RenderData(cli, oldItem, options, false, temp.Item8); + cli.MoveCursorBy(-x2 - temp.Item8, -y2); + }; + + if (temp.Item3 > 0 && select >= temp.Item1 && select < (temp.Item1 + temp.Item2)) + { + cli.BackspaceToBeginning(); + var h = temp.Item3 + (temp.Item5 ? 2 : 1) + (temp.Item6 ? 1 : 0); + if (oldSelect != select) resetSelect(); + if (select < 0 || select >= list.Count) select = 0; + var item = list[select]; + var y = Math.DivRem(select % temp.Item7, temp.Item4, out var x) - h; + x *= temp.Item8; + cli.MoveCursorBy(x, y); + RenderData(cli, item, options, true, temp.Item8); + cli.MoveCursorBy(-x - temp.Item8, -y); + RenderSelectResult(cli, item?.Title, options); + } + else + { + if (temp.Item3 > 0) + { + cli.BackspaceToBeginning(); + var h = temp.Item3 + (temp.Item5 ? 2 : 1) + (temp.Item6 ? 1 : 0); + for (var i = 0; i < h; i++) + { + cli.MoveCursorBy(0, -1); + cli.Clear(StyleConsole.RelativeAreas.Line); + } + } + + temp = RenderData(cli, list, options, select); + } + + oldSelect = select; + ConsoleKeyInfo key; + try + { + key = cli.ReadKey(); + } + catch (InvalidOperationException) + { + return SelectByManualTyping(cli, collection, options); + } + catch (IOException) + { + return SelectByManualTyping(cli, collection, options); + } + catch (SecurityException) + { + return SelectByManualTyping(cli, collection, options); + } + catch (NotSupportedException) + { + return SelectByManualTyping(cli, collection, options); + } + + switch (key.Key) + { + case ConsoleKey.Enter: + case ConsoleKey.Select: + case ConsoleKey.Spacebar: + if (select < 0 || select >= list.Count) + { + select = temp.Item1; + if (select < 0 || select >= list.Count) + select = 0; + break; + } + + var sel = list[select]; + RenderSelectResult(cli, sel?.Title, options); + cli.WriteLine(); + return new SelectionResult(sel.Title, select, sel.Data, sel.Title); + case ConsoleKey.Backspace: + case ConsoleKey.Delete: + case ConsoleKey.Clear: + cli.WriteImmediately(' '); + cli.BackspaceToBeginning(); + resetSelect(); + return SelectByManualTyping(cli, collection, options); + case ConsoleKey.Escape: + case ConsoleKey.Pause: + cli.WriteImmediately(' '); + cli.BackspaceToBeginning(); + resetSelect(); + RenderSelectResult(cli, null, options); + cli.WriteLine(); + return new SelectionResult(string.Empty, SelectionResultTypes.Canceled); + case ConsoleKey.Help: + case ConsoleKey.F1: + { + cli.BackspaceToBeginning(); + resetSelect(); + RenderSelectResult(cli, "?", options); + cli.WriteLine(); + var item = collection.Get('?', out select); + return item == null + ? new SelectionResult("?", SelectionResultTypes.Selected) + : new SelectionResult("?", select, item.Data, item.Title); + } + case ConsoleKey.F4: + if (temp.Item3 > 0) + { + cli.BackspaceToBeginning(); + var h = temp.Item3 + (temp.Item5 ? 2 : 1) + (temp.Item6 ? 1 : 0); + for (var i = 0; i < h; i++) + { + cli.MoveCursorBy(0, -1); + cli.Clear(StyleConsole.RelativeAreas.Line); + } + } + + return SelectByManualTyping(cli, collection, options, true); + case ConsoleKey.F5: + if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) + select = 0; + break; + case ConsoleKey.F6: + cli.BackspaceToBeginning(); + resetSelect(); + RenderSelectResult(cli, null, options); + cli.WriteLine(); + if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) + select = 0; + temp = RenderData(cli, list, options, select); + break; + case ConsoleKey.F12: + { + cli.BackspaceToBeginning(); + resetSelect(); + RenderSelectResult(cli, "?", options); + cli.WriteLine(); + var item = collection.Get('?', out select); + return item == null + ? new SelectionResult("?", SelectionResultTypes.Canceled) + : new SelectionResult("?", select, item.Data, item.Title); + } + case ConsoleKey.PageUp: + if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) + select = 0; + else + select = Math.Max(0, temp.Item1 - temp.Item7); + break; + case ConsoleKey.PageDown: + if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) + select = list.Count - 1; + else + select = Math.Min(list.Count - 1, temp.Item1 + temp.Item7); + break; + case ConsoleKey.UpArrow: + if (select < temp.Item4) + { + select += list.Count - (list.Count % temp.Item4); + if (select >= list.Count) select -= temp.Item4; + if (select >= list.Count) select = list.Count - 1; + else if (select < 0) select = 0; + } + else + { + select -= temp.Item4; + } + + break; + case ConsoleKey.DownArrow: + select += temp.Item4; + if (select >= list.Count) + { + select %= temp.Item4; + if (select >= list.Count) select = list.Count - 1; + } + + break; + case ConsoleKey.LeftArrow: + select--; + if (select < 0) select = list.Count - 1; + break; + case ConsoleKey.RightArrow: + select++; + if (select >= list.Count) select = 0; + break; + case ConsoleKey.Home: + if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) + select = 0; + else + select = temp.Item1; + break; + case ConsoleKey.End: + if (key.Modifiers.HasFlag(ConsoleModifiers.Control)) + select = list.Count - 1; + else + select = temp.Item1 + temp.Item2 - 1; + break; + default: + { + var item = collection.Get(key.KeyChar, out select); + if (item == null) + { + select = oldSelect; + continue; + } + + cli.WriteImmediately(' '); + cli.BackspaceToBeginning(); + resetSelect(); + RenderSelectResult(cli, item.Title, options); + cli.WriteLine(); + return new SelectionResult(item.Title, select, item.Data, item.Title); + } + } + } + } + + /// + /// Tests if the input string is to get help. + /// + /// The input string. + /// true if to get help; otherwise, false. + public static bool IsAboutToGetHelp(string s) + => !string.IsNullOrEmpty(s) && s.Trim().ToLowerInvariant() switch + { + "?" or "help" or "gethelp" or "get-help" or "-?" or "/h" or "--?" or "-help" or "--help" or "/help" or "帮助" or "bangzhu" or "/bangzhu" or "--bangzhu" or "获取帮助" or "助け" or "❓" => true, + _ => false + }; + + /// + /// Tests if the input string is to exit. + /// + /// The input string. + /// true if to exit; otherwise, false. + public static bool IsAboutToExit(string s) + => !string.IsNullOrEmpty(s) && s.Trim().ToLowerInvariant() switch + { + "exit" or "quit" or "close" or "bye" or "byebye" or "goodbye" or "good-bye" or "end" or "shutdown" or "shut-down" or "关闭" or "退出" or "再见" or "guanbi" or "tuichu" or "zaijian" or "さようなら" => true, + _ => false + }; + + /// + /// Writes a collection of item for selecting. + /// + /// The type of data. + /// The command line interface proxy. + /// The collection data. + /// The selection display options. + /// The index of item selected. + /// The result of selection: offset, count, rows, columns, paging tips, customized tips, page size, item length. + private static (int, int, int, int, bool, bool, int, int) RenderData(this StyleConsole cli, List> collection, SelectionConsoleOptions options, int select) + { + var maxWidth = GetBufferSafeWidth(cli); + var itemLen = options.Column.HasValue ? (int)Math.Floor(maxWidth * 1.0 / options.Column.Value) : maxWidth; + if (options.MaxLength.HasValue) itemLen = Math.Min(options.MaxLength.Value, itemLen); + if (options.MinLength.HasValue) itemLen = Math.Max(options.MinLength.Value, itemLen); + if (itemLen > maxWidth) itemLen = maxWidth; + var columns = (int)Math.Floor(maxWidth * 1.0 / itemLen); + if (options.Column.HasValue && columns > options.Column.Value) columns = options.Column.Value; + var maxRows = 50; + try + { + maxRows = Console.BufferHeight - 5; + if (maxRows < 1) maxRows = 50; + } + catch (InvalidOperationException) + { + } + catch (IOException) + { + } + catch (SecurityException) + { + } + catch (NotSupportedException) + { + } + + if (options.MaxRow.HasValue && options.MaxRow.Value < maxRows) + maxRows = options.MaxRow.Value; + var pageSize = columns * maxRows; + var needPaging = collection.Count > pageSize; + if (select >= collection.Count) select = collection.Count - 1; + var list = collection; + var offset = 0; + if (select >= pageSize) + { + offset = (int)Math.Floor(select * 1.0 / pageSize) * pageSize; + list = list.Skip(offset).Take(pageSize).ToList(); + } + else if (needPaging) + { + list = list.Take(pageSize).ToList(); + } + + var i = offset; + var lastColIndex = columns - 1; + var rows = -1; + SelectionItem selItem = null; + foreach (var item in list) + { + if (string.IsNullOrEmpty(item.Title)) continue; + var isSel = i == select; + if (isSel) selItem = item; + RenderData(cli, item, options, isSel, itemLen); + var indexInRow = i % columns; + if (indexInRow == lastColIndex) + cli.Write(Environment.NewLine); + else if (indexInRow == 0) + rows++; + i++; + } + + if (list.Count % columns > 0) cli.Write(Environment.NewLine); + var hasPagingTips = false; + var tipsP = options.PagingTips; + if (needPaging && !string.IsNullOrEmpty(tipsP)) + { + cli.Write( + new ConsoleTextStyle( + options.PagingForegroundRgbColor, + options.PagingForegroundConsoleColor ?? options.ForegroundColor, + options.PagingBackgroundRgbColor, + options.PagingBackgroundConsoleColor ?? options.BackgroundColor), + tipsP + .Replace("{from}", (offset + 1).ToString()) + .Replace("{end}", (offset + list.Count).ToString()) + .Replace("{count}", list.Count.ToString("g")) + .Replace("{size}", pageSize.ToString("g")) + .Replace("{total}", collection.Count.ToString("g"))); + cli.Write(Environment.NewLine); + hasPagingTips = true; + } + + var hasTips = false; + if (!string.IsNullOrEmpty(options.Tips)) + { + cli.Write( + new ConsoleTextStyle( + options.TipsForegroundRgbColor, + options.TipsForegroundConsoleColor ?? options.ForegroundColor, + options.TipsBackgroundRgbColor, + options.TipsBackgroundConsoleColor ?? options.BackgroundColor), + options.Tips.Length < maxWidth - 1 + ? options.Tips + : (options.Tips.Substring(0, maxWidth - 5) + "...")); + cli.Write(Environment.NewLine); + hasTips = true; + } + + RenderSelectResult(cli, selItem?.Title, options); + return (offset, list.Count, rows, columns, hasPagingTips, hasTips, pageSize, itemLen); + } + + private static void RenderSelectResult(StyleConsole cli, string value, SelectionConsoleOptions options) + { + cli.Write( + new ConsoleTextStyle( + options.QuestionForegroundRgbColor, + options.QuestionForegroundConsoleColor ?? options.ForegroundColor, + options.QuestionBackgroundRgbColor, + options.QuestionBackgroundConsoleColor ?? options.BackgroundColor), + options.Question); + if (!string.IsNullOrWhiteSpace(value)) + cli.WriteImmediately(options.ForegroundColor, options.BackgroundColor, value); + else + cli.Flush(); + } + + private static void RenderData(StyleConsole cli, SelectionItem item, SelectionConsoleOptions options, bool isSelect, int len) + { + var style = isSelect ? new ConsoleTextStyle( + options.SelectedForegroundRgbColor, + options.SelectedForegroundConsoleColor ?? options.ForegroundColor, + options.SelectedBackgroundRgbColor, + options.SelectedBackgroundConsoleColor ?? options.BackgroundColor) : new ConsoleTextStyle( + options.ItemForegroundRgbColor, + options.ItemForegroundConsoleColor ?? options.ForegroundColor, + options.ItemBackgroundRgbColor, + options.ItemBackgroundConsoleColor ?? options.BackgroundColor); + var sb = new StringBuilder(); + var j = 0; + var maxLen = len - 1; + var curLeft = TryGetCursorLeft(cli) ?? -1; + foreach (var c in (isSelect ? options.SelectedPrefix : options.Prefix) ?? string.Empty) + { + var c2 = c; + switch (c) + { + case '\t': + case '\r': + case '\n': + j++; + c2 = ' '; + break; + case '\0': + case '\b': + continue; + default: + j += GetLetterWidth(c); + break; + } + + if (j >= maxLen) break; + sb.Append(c2); + } + + foreach (var c in item.Title) + { + var c2 = c; + switch (c) + { + case '\t': + case '\r': + case '\n': + j++; + c2 = ' '; + break; + case '\0': + case '\b': + continue; + default: + j += GetLetterWidth(c); + break; + } + + if (j >= maxLen) break; + sb.Append(c2); + } + + if (curLeft >= 0) + { + cli.WriteImmediately(style, sb); + var rest = curLeft + len - cli.CursorLeft; + if (rest > 0) + cli.WriteImmediately(style, ' ', rest); + else if (rest < 0) + cli.WriteImmediately( + new ConsoleTextStyle( + options.ItemForegroundRgbColor, + options.ItemForegroundConsoleColor ?? options.ForegroundColor, + options.ItemBackgroundRgbColor, + options.ItemBackgroundConsoleColor ?? options.BackgroundColor), + " \b"); + } + else + { + sb.Append(' ', len - j); + cli.WriteImmediately(style, sb); + } + + try + { + if (curLeft >= 0) + { + curLeft += len; + var rest = curLeft - cli.CursorLeft; + if (rest < 0) + { + cli.MoveCursorBy(rest, 0); + cli.WriteImmediately( + new ConsoleTextStyle( + options.ItemForegroundRgbColor, + options.ItemForegroundConsoleColor ?? options.ForegroundColor, + options.ItemBackgroundRgbColor, + options.ItemBackgroundConsoleColor ?? options.BackgroundColor), + " \b"); + } + else if (rest > 0) + { + cli.MoveCursorBy(rest, 0); + } + } + } + catch (InvalidOperationException) + { + } + catch (IOException) + { + } + catch (SecurityException) + { + } + catch (NotSupportedException) + { + } + } + + private static int GetLetterWidth(char c) + { + if (c < 0x2E80) return 1; + return c < 0xA500 || (c >= 0xF900 && c < 0xFB00) || (c >= 0xFE30 && c < 0xFE70) + ? 2 + : 1; + } + + /// + /// Asks to type the item keyword. + /// + /// The type of data. + /// The command line interface proxy. + /// The collection data. + /// The selection display options. + /// true if list all data before typing; otherwise, false. + /// The result of selection. + private static SelectionResult SelectByManualTyping(StyleConsole cli, SelectionData collection, SelectionConsoleOptions options, bool listAllData = false) + { + cli.BackspaceToBeginning(); + int i; + if (listAllData) + { + var maxWidth = GetBufferSafeWidth(cli); + var itemLen = options.Column.HasValue ? (int)Math.Floor(maxWidth * 1.0 / options.Column.Value) : maxWidth; + if (options.MaxLength.HasValue) itemLen = Math.Min(options.MaxLength.Value, itemLen); + if (options.MinLength.HasValue) itemLen = Math.Max(options.MinLength.Value, itemLen); + if (itemLen > maxWidth) itemLen = maxWidth; + var columns = (int)Math.Floor(maxWidth * 1.0 / itemLen); + if (options.Column.HasValue && columns > options.Column.Value) columns = options.Column.Value; + var list = collection.ToList(); + i = 0; + var lastColIndex = columns - 1; + var rows = -1; + foreach (var ele in list) + { + if (string.IsNullOrEmpty(ele.Title)) continue; + RenderData(cli, ele, options, false, itemLen); + var indexInRow = i % columns; + if (indexInRow == lastColIndex) + cli.Write(Environment.NewLine); + else if (indexInRow == 0) + rows++; + i++; + } + + if (list.Count % columns > 0) cli.Write(Environment.NewLine); + return SelectByManualTyping(cli, collection, options); + } + + cli.WriteImmediately( + new ConsoleTextStyle( + options.QuestionForegroundRgbColor, + options.QuestionForegroundConsoleColor ?? options.ForegroundColor, + options.QuestionBackgroundRgbColor, + options.QuestionBackgroundConsoleColor ?? options.BackgroundColor), + options.ManualQuestion ?? options.Question); + string s; + try + { + s = cli.ReadLine(); + } + catch (IOException) + { + return new SelectionResult(string.Empty, SelectionResultTypes.NotSupported); + } + catch (InvalidOperationException) + { + return new SelectionResult(string.Empty, SelectionResultTypes.NotSupported); + } + catch (ArgumentException) + { + return new SelectionResult(string.Empty, SelectionResultTypes.NotSupported); + } + catch (NotSupportedException) + { + return new SelectionResult(string.Empty, SelectionResultTypes.NotSupported); + } + + if (string.IsNullOrEmpty(s)) + return new SelectionResult(s, SelectionResultTypes.Canceled); + SelectionItem item = null; + if (s.Trim().Length == 1) + { + item = collection.Get(s[0], out i); + if (item != null) + return new SelectionResult(s, i, item.Data, item.Title); + } + + i = -1; + foreach (var ele in collection.ToList()) + { + i++; + if (ele.Title != s) + continue; + item = ele; + break; + } + + return item == null + ? new SelectionResult(s, SelectionResultTypes.Typed) + : new SelectionResult(s, i, item.Data, item.Title, SelectionResultTypes.Typed); + } + + /// + /// Writes a collection of item for selecting. + /// + /// The type of data. + /// The command line interface proxy. + /// The collection data. + /// The selection display options. + /// The result of selection. + private static SelectionResult SelectForText(StyleConsole cli, SelectionData collection, SelectionConsoleOptions options) + { + var list = collection.ToList(); + cli.WriteLines(list.Select((ele, i) => $"#{i + 1}\t{ele.Title}")); + var style = new ConsoleTextStyle( + options.QuestionForegroundRgbColor, + options.QuestionForegroundConsoleColor ?? options.ForegroundColor, + options.QuestionBackgroundRgbColor, + options.QuestionBackgroundConsoleColor ?? options.BackgroundColor); + cli.Write(style, options.QuestionWhenNotSupported ?? options.ManualQuestion ?? options.Question); + string text; + try + { + text = cli.ReadLine(); + } + catch (NotSupportedException) + { + return new SelectionResult(null, SelectionResultTypes.NotSupported); + } + catch (InvalidOperationException) + { + return new SelectionResult(null, SelectionResultTypes.NotSupported); + } + catch (IOException) + { + return new SelectionResult(null, SelectionResultTypes.NotSupported); + } + catch (ArgumentException) + { + return new SelectionResult(null, SelectionResultTypes.NotSupported); + } + + if (string.IsNullOrEmpty(text)) + { + cli.Write(style, options.QuestionWhenNotSupported ?? options.ManualQuestion ?? options.Question); + text = cli.ReadLine(); + if (string.IsNullOrEmpty(text)) + return new SelectionResult(text, SelectionResultTypes.Canceled); + } + + SelectionItem item = null; + int i; + if (text.Trim().Length == 1) + { + item = collection.Get(text[0], out i); + if (item != null) + return new SelectionResult(text, i, item.Data, item.Title); + } + +#pragma warning disable IDE0057 + if (text.StartsWith("#") && int.TryParse(text.Substring(1).Trim(), out i) && i > 0 && i <= list.Count) + { + item = list[i]; + return new SelectionResult(text, i, item.Data, item.Title); + } +#pragma warning restore IDE0057 + + i = -1; + foreach (var ele in list) + { + i++; + if (ele.Title != text) + continue; + item = ele; + break; + } + + if (item != null) + return new SelectionResult(text, i, item.Data, item.Title, SelectionResultTypes.Typed); + + if (int.TryParse(text.Trim(), out i) && i > 0 && i <= list.Count) + { + item = list[i]; + return new SelectionResult(text, i, item.Data, item.Title); + } + + return new SelectionResult(text, SelectionResultTypes.Typed); + } +} diff --git a/Console/Console.csproj b/Console/Console.csproj new file mode 100644 index 0000000..1a033e7 --- /dev/null +++ b/Console/Console.csproj @@ -0,0 +1,39 @@ + + + + + + net8.0;net6.0;net48;net462;net461 + Trivial.Console + Trivial + Trivial.Console + The rich user interface console controls and utilities. + https://github.com/nuscien/trivial/wiki/console + true + true + snupkg + cmd.png + https://github.com/nuscien/trivial/raw/master/Materials/logo.png + console + + + + + + + + + True + True + Resource.resx + + + + + + ResXFileCodeGenerator + Resource.Designer.cs + + + + diff --git a/Console/README.md b/Console/README.md new file mode 100644 index 0000000..fb73391 --- /dev/null +++ b/Console/README.md @@ -0,0 +1,122 @@ +# [Trivial.Console](https://trivial.kingcean.net/cmdline) + +This library includes a lot of useful rich command line controls. + +## Import + +Add following namespace to your code file to use. + +```csharp +using Trivial.CommandLine; +``` + +## Select + +A beautiful list or table with customized style to the standard output stream +so that user just need press the arrow buttons and `ENTER` in keyboard to select. + +```csharp +// Create an instance for adding items and setting options. +var col = new Trivial.Collection.SelectionData(); + +// Add some items. For each item, you can set a hotkey, a display name and the data. +col.Add('a', "char a", "a"); +col.Add('b', "char b", "b"); +for (var i = 0; i < 120; i++) +{ + col.Add("num " + i, i.ToString()); +} + +// Create an options for display. +var options = new SelectionOptions +{ + // You can define a question string after the list. + Question = "Please select one: ", + + // We can define the colors of the item selected. + SelectedForegroundConsoleColor = ConsoleColor.White, + SelectedBackgroundConsoleColor = ConsoleColor.Blue, + + // The selected item will also be displayed after the question string. + // So you can define its color. + ItemForegroundConsoleColor = ConsoleColor.Cyan, + + // At the end of the list, the tips will be displayed before user press any key. + // There is a default value and you can customize it. + // And you can disable it by set it as null. + Tips = "Tips: You can use arrow key to select and press ENTER key to continue.", + + // Then you can define its color. + TipsForegroundConsoleColor = ConsoleColor.Yellow, + + // You can define the prefix for the item and the one selected. + SelectedPrefix = "> ", + Prefix = " ", + + // You can define the column count for the list. + Column = 5, + + // You can define the maximum rows to displayed. + // A paging will be displayed if the count of the list is greater than it. + MaxRow = 10, + + // Press ESC can cancel this selection. + // But you can enable the manual way by set a manual question + // so that user can type the words directly. + ManualQuestion = "Type: " +}; + +// Write it to the standard output stream and wait for user selection. +var result = DefaultConsole.Select(col, options); + +// You can get the result. +DefaultConsole.WriteLine("The result is {0}.", result.Value); +``` + +## Progress + +A progress bar in terminal that can present the latest state during the specific task running. + +```csharp +// Define an options that you can custom the style. +var progressStyle = new ConsoleProgressStyle +{ + ValueConsoleColor = ConsoleColor.White +}; + +// Ouput the component in console and get the progress instance to update. +var progress = DefaultConsole.WriteLine(progressStyle, "Processing"); + +// A time-consuming work here. +for (var i = 0; i <= 50; i++) +{ + await Task.Delay(10); + + // And report the progress updated. + progress.Report(0.02 * i); +} +``` + +## JSON + +Following is a sample to format JSON into terminal. + +```csharp +var json = new Trivial.Text.JsonObjectNode(); +// and then add some properties to json. +DefaultConsole.WriteLine(json); +``` + +## Linear gradient + +Output a string with linear gradient. + +```csharp +DefaultConsole.WriteLine(new LinearGradientConsoleStyle( + ConsoleColor.Gray, // Fallback color. + Color.FromArgb(15, 250, 250), // From color. + Color.FromArgb(85, 168, 255)) // To color + { + Bold = true // Additional font style + },"Trivial Sample"); +``` diff --git a/Demo/Demo.csproj b/Demo/Demo.csproj index d1dd38b..2de61c0 100644 --- a/Demo/Demo.csproj +++ b/Demo/Demo.csproj @@ -1,15 +1,13 @@  + + + WinExe net7.0-windows10.0.19041.0 10.0.17763.0 - 7.1.0 - 7.1.0.0 - 7.1.0.0 Trivial.WindowsKit.Demo Trivial.WindowsKit.Demo - Kingcean Tuan - Nanchang Jinchen Software Co., Ltd. Trivial.Demo app.manifest ..\Materials\WinKit.ico @@ -18,17 +16,10 @@ win10-$(Platform).pubxml true true - True - ..\Trivial.snk - - - - ..\bin\Debug\ - ..\bin\$(Configuration)\$(TargetFramework)\Trivial.WindowsKit.Demo.xml - - ..\bin\Release\ + + ..\bin\$(Configuration)\ ..\bin\$(Configuration)\$(TargetFramework)\Trivial.WindowsKit.Demo.xml diff --git a/Materials/cmd.png b/Materials/cmd.png new file mode 100644 index 0000000000000000000000000000000000000000..1909b974c193a51fae19d05f07582bcda2352305 GIT binary patch literal 98962 zcmeFa2T+tt*Qoo>Fk}e=f(aOjA~`3Cf}%tL36ir&7;=UgP((!mK|wMqNCpKFkT8RY zh(yVfL4xGW5GI_#u(#jG{yhJG|8wuHQzccqW?buCtGl0Gy?S-ORkQEtXkDP9I8Ffo z0M$h`62UNFyV zFgNJMbLXIL9x!`HXFCA!8%WjjHHt$s%8#P$XbhD5S6(JKhXQQu1!Ny+ji1uS0#-L^ z=@c8nZ&MgB966k#cI91I4~1Il?TL)j6%I;wZ(ohPVk))7I+R@&9I(8&xYxH=J(Dtn zY4dNVK^&&zdNBR;Iv}kZepaTRHCkKkT~iGLd_-*w0;Qd9e(ONo001jQ{(d1|FBCAK zVi;jGZao4VbdBTq8*g;D3<2l^V2q7!h7uH`3w#jJ|G)rzI10SbE48Hn9s+=~e~>a8 zkVge9Y+RHl2Ksa3hM0i}_uwoTpc_mbr4~%*XWE3c}2|!RqAcXO2 zkqcl%4Kd&oWfViBXbB(^mHAo#s1z7D$3ovq1l1tQ5b8vZmU#wJcpymfx5Y{kSwYfnDOmXeUnPOmmYq|tT=0FLi`s>4Ys#LP@jj!)aq zI4^HBJjFS!z}VzZt&ZZV?|~rztycT;fW_2QFOgd#=!G}ZDc1xTFaWNN?wE-Vl4o3{ z=m^+}^q0aYvZOuH`EZu`Bn2hqBB%9}8lf+d@_5m4*jQx97D0;}3|Il&lN1vRQO|B* z-K|`Gigcr9njy-C`2_%~zaBNsdB~*ko(up~GD6S1P$E54$54QxPN`$AMlpe{NK_OLaiGr9Dw9ki zPEtHM8n1LrA0^WdDSJV5JmYZEIPI%CVJWJaF*?)Gc{e5!%cE&;k5=CzhbVm@qqjOG zbNjG$R6koA8B<~ugw0A#EEbUooxRO)nXTc2MSfAz(mJMSaLvcKG>uG>l^_bB2@lF+XkxTu z_nPV_%Nb-EZck{CKjqNPd`Ndm+)iN%l9eu^oS2b!xivSfn=J3PO#0P}E*U;Lf_f3T z^kUvgoUO@>=bAJ5pY?PkIXXC^uL;h2y&)gI!J?YbkLHr7BmVs7=>bH(ICtvct`y{W;}Q+o?9Hwm^O&eg*!Qz1Iuv3quMe2Lc9a2do!878w`k z2bR6vQWaDAQa5E>WYFH^ZzSGaeiQy?(7Sz3zRPCbf0lgn<0kd&@TUu#E*sA_ndX*z zmp`#e3WGP zYCl&GV(y1$sirhsij;_Kj30;(Y9@}?j7JwdHjp>)H`p}jE4bKeI?p%n(rf6fbHXtB zP_j&N^Xr_#jgm<5W3qy>^i=`E`*&MlX%cIK9obj-c7 zUa~>~7jJ%xPZrd!8{CjzDdO&(a?eki;QMp?7klv8Q z5K>Iqp6qTjHhLR5?!U&kszq!Gssl}dYC?~PmJ&G;u|g6dS)}5`_lc`W1P{p{Q9eXY zWz6ak2SYKfo!GGv9dh7H`gG(YS?ZCiCw7HexHMRL4@cc=fj!^Rm~DAYc6;oC z^X&>&$76|1JHZS*XGHP@<}Sa|^K$n>^Ys=?8t*yOM6E{W-m8=yy#Ct5$D!c5v#ztv zLUIM7BCjIUFJfDDHG$5Ho`Zbx&g8rPcXD^Wc!Fn~lSES{ll0@gY>K9ao>nqV&$czE z`JOcvH;xIC3V%$OP@*t(1FEbecvO2T+f|d9e(h#*xVCET)B8^^zbvn~bT)Q6)!@;V z)Ua&ux!r5Gw9k9L7bVx$<@JAXEVhz;UDH6Ncch^Gv-@X$>4zx~Q=aKkImW-@?Gq|L zU9N4<%Ns{E=|AoA@kCt2NAx87j_3N|5$AA?PtRWI7U@tkY6#}=`k5Rx@vBg)QM=kL zI%zub7@N)UxOa+VpoB7#O)!{&8_$Z9a3}wE%65EWT88U8$$z)(TbOiPig4CoEhp zjd(o?xV{w>|xClb%L0#e~-%?8-Q{PNn*Tm!wxVc)=Y>Kn{Q zWJi`CE>xHC`WZUas0MGkb}oetM<2I7@dh~^GF)-NSGyrCIxs7cbW3%4{<;^;d8inP zEFpK%mAKEMCgV1hjDQU!FDChxxm`U&{Z?tJj(hZZP~aDxuTR?Qhw58L6XE5XWbs=dzQ*<&U~S^93QeQ{Kdw*Q9Rl(EhF``-0IF`SlpLv+w8Pd zEd{ym#36sQ1}4$T?6O&n!@2e}1tza0jdBZg)B4CvwAo6v+XfrjdXTeRy-==5?m~zg zc3iF41U7GnZeBDzTjaH&IWPNZxeLB~9o6I6x7{aTmhNA({C?p?xhvQ3$qLRlo7+BH zi%h;0OBzFF0nvWNnA!pC9O*929Q+mTr5(y;Y}*oL*NQ}vgzADh8W=e=RNahMzIrn>g`6D{uRod$aZ9rf9|@+ za(-^HOe1?EYjvBy-0E{oVcTHva>eqS(Z(9q#M2l>oX+~EU7N=24sEpjOb`wuh`zbL z$Jv=K3INJnj`~JkMw%KjHZT_fD_fYgoq(T<8=(vZfU^pIZdNugt+i?7T-^R@$kp=)I|4;PKPxvuVF4k*e=@SQ`OC)5+r#-=*KBPB?VRmg z>|DJ(33kH&Xh%S*sri@bKQ`y$@{g9DUaCHX5&R(XkCvYL{%&@Hx^|v0Zx0(gRUbl6 z*#D{Xo?g0kf5ZJRxFS6MkB;1a9%TNxUw^6pBStSr`~T39ea(L~v-5NO4`%zC?`Gd( z>iblmB~X_+=V52%1@q8{!JOs4hwIJ@43bnWj^3qSpL` zo=fmc*ojH;TT9#9^4kariAf6!NlM$=ivDckAKV;hO3l%e5O@B+#3Lapza=|8JNJK; z{!}E z&gSPd|97WBf?rr{KVJz;$OsGl%ryW1O~c<&Y;(=Z)xpkIUhwD0ehU6?nmHROJ3CQ( zAuE1cQ6VvYF-bx`w3Z^woQSO2e-${Rj zBx^+|XYD*ZJ5sH)ls1tNm0e=;LbpqaOTg2ZDORpucRB-?{(dSn(_CX{(9-=p*V z{+im~VhPdrzbR%2^$6jhA@j>l_OrbFucp&~Gyj*h_`^G)p!|J>DK2d-C1!0cMyO(? z2=(l@3e!eXh)`jQh+7LwNZQ&8i|?oI{kDE__D^lW{-;Ie_g4PF&EKv4oQGd<|5D1F z{VQ+DoP#;TJTzgpcJhSk^`FGQ`21To9J#;+szT@TOh zpGIW}#Xh0%{I)a569#`k_RGM(>5TS^c4zNzMY*WZw?9GQ{f{5Ezv}X!n zZT~jC;_B!nFY=?ge-r;=wSQ>-9v^yyiz2)I!Tr1F-=EfT^s{p|QgI|4);#wQ9pb`- zX1*EyyXGG)jsK(NFPa~g-zV;u3!QI4@?A=}E+X7i3I26ebs&CzO=JJZzW+U>|6?u> zI{MSdK_1qN%04D$-ZUDdzp71#f0Nz3X zFlPw>GLHd(2^MS7a2^1O-@mA$r0+MdP~$t~Y-lEc3+fxu8x094mX>b12va2E@B$5% znIG2Cha9QNFz?O}yF0X2YT8Z7sG~Gnb6Pc&_BxcD_L7?NZqw|h+zh`SdKZW54{R@} zv0s!6+^t?V=1p%(^tEqKlB+71@vnVURJA12Zxz98BYL{Q$<|Mce7T`DS*)Vf)3r2p zcDbT&;YEGa;X{2aVA+MEvK`TTgB!4K4H90357UVvC}d5L)QiOpw zRw_Hpoi0#x(uMk5w}7+Y_{&_f*344E4jJiMMli<%{Z@^{#F&egtfU*yFI2c(WsA85 zd5o|)P6iOUy+W$4z|cGMan=1hFVqzr3(vbBj73elQ(M1(SL;Rv* zdKo%%Jh*ejum^66L3q;>M!^aA^t;#PU^x&l^w~Smcg93ASMXej1ZMech_aGUBW(;P z*r(r$9Kq~U;5BAA+6B7$YA0bV`LkxbD)?ds3z=fdgkie+qImmCEzbDK*#w@g20D=J z!V3stkOmCfq+63ln<$uOx&jc1IiwCD0HXtB7mPlk zXx{CuX^!!~LNeETTKTn$T_`s|_>2|D0n8h6#4A_W#;y(CIU1>S^6-nguphm;$Gx`Pc`ENo#h&~8L|?shdpyRMi`%Gt9ZINZd~?BbEb-Jyy!bfKa_H&Gs1y=O zF~J4Ske>rY21a)!l-a?VMnv7q2BGQJYKXu4Bhr%&!CkyG+5?QbtQRLjXvx*0b@&7I zi%X1T3>nP}+mtH+at${WIM2xCmtq78Txmd`YV!CgZUu;#g@Gy5}a#Z-)&Ph z9v!pzNq@u_Tb=w8DR{}GZ6tN^=aQmYt3Kz=5|b^#;?LF6RY4(#!*b%AriMGME34-} zYPyM1GqyccBlBouF<~1=QIMvKb9QuwdI>F0AdS$^=e|8LD4t(*5|> zD{7ton2)Hj?HXh{0F3G@i(p#!-7eN43(e-i$3WFo%#OU-E$8^LUZS3aAt|sHs#^QGro&EsZ2a%$IRzS?=(TBe>}0`vF5 z?heQ(%aKZX!@09od~*!WWg?2*u<$#f$9F82QW|M0W)dT3qEbH$p{Gb~XM^}H&>t%! zYD18FUxy=x8%iB&=%Z8PD(~D&Noi&?`JhC0j5bULkwmg3PIM}VG|&nR*98cC(U63lE^~F94(i&w1Zvdy5Q)Po=?9DOal%t6|?eOh;ek)O=PT`4sTr;L*mx(=9*?}I2vgOA!9pngHaT(-C zj`~EuJ^u)!--YD4-)=k5ejL{tszUvUQ_3MK{+iDh)5WA2)3Tt&^&+#{wdv;Raz<{y zV{QquLi3)>Mk72cjWtVCh=8{8LmDX{iJ%D!yv>}#$o9pPfh*VeCCArVZtQL< z!#?D^nde~Uy*7hGN4A;O27A^}OU+<%uu*dZS;V*yWftFUd7@av00eO?LyE>3^R7x> zZhfS$8fk8Bw9@O64!LvYar1HVoYNc`15dIztb**q0euFrj?x}fsmw5x6Xer>STu#-)vbAq+)B2R$HMv0j?T174at7 zdbSq{HG>hD5K4}97G4>cD?Jt~_$;=Yr#o}cJsO($e07!+=J%=2ux6`)Qo6B~nG|vY z%1iv=`P)rlv7JU1|1~q#S7iDgs7h{g|HD3V^B-rIN8J^ohJ0hQdo{v7=m)qG_-KK03QLfbuVq)#E`7-E`&rW3^&HP-7n(qN&$vl@(T_@MY+%Q&-k*^|i95f- zO|`9=k?sP*-D-k=YE3y?@pX73ESU!XX)k1E@{z1$Bs~b_O@_<8vHjk7)7Q<1EQIUb z+W}|S+4rpQIhEF_w`kX@zBpZ|VM|ydof_c%qHli;ZT|X+iM}~ zvA&s5aRHQl<9Z0w!@1>&Lo%JPz_aj8RTIw>MI*vHS?J+oF$gJN#Q_Y(elPcnP`>TP zFk~L)8Hb|OzOy{hQpe%kzL2lJQ3{LCo8P$;VJ1W=;49cv0evdE7rvf8^*w{xwHs+wXN%t_$tq$E{zic&#+W?Awx`GLOmU_J zw91-$Z-16t@MI-5l?GO3ARXN6(+gm8mK<$x8^f69j@gcgouWQ)IpM6gPl$21qCRMd z??HL!hh&H;6N*8nl^CMTNrv^hoOz$LgAX)QG*T*EwVK4NXW<-!s1AjAm0TbMjk^-{ z{xO3v4-lMx%<0b0&o-SaH5}k*7eNKwssXAtH_aM>e=m<8Tj zS`->IQ(U-{&xCU!UJAlJn*=t_}bH3xtSFMPJ7h|J`x3xPujb}xU zv|;B)t0z}zlXJR7#B{3Q$%zx7!dHLzmr%E4<0p>ZX(m}V2<6g2*gCB z2bxXi^u8@OT+v>;BRWQ|ShN|u@!1BIG^pUyx6p{6?wSadWyvM4J6k5v9L~e!daKT~ z4`|f`?$bLTQkHdX4Ixtzc+7lN>PoAAv$sZJa=uILwdS{7A>;2$C2?Q9v+hGH$tq@U zG))|uPFbRTSEHoH0lGK4`SzDS@xr-9m9nV~N~U5T z4p+vc-MC6@?KtAe+uT{T{a$X0H{G)#(V=?#c_~w2>U(LFnS>F9E<==RJDUUah7-yG z{(DQ&cG(i_oINM*VBhsd6uF~~48Xk4M|a%Wvd5=gfm_ZM7lAw=EhE^m2Z@6tyIB+2 z_}R$K&K*1Ha_M&ZQtF#IH!6=4S$6{VbcF(dUNCm$af7(32a!k&sQD0oO0MjTmj1i= zNXbLd(0@%+olsVt_hiFoGibBIqxaZnC z{7(6(G^SvGnL|#x65-_XLShy9NiC^_&^6~AdP5fQ!Ed&+&_m|D{Ct7)<=W7=b*P;< zP<$1PxHx5TWZUkou=rshtWw;AYk6D}IYSPci^I3qd3tIu}~k(+iG(s3>MLpQGKrMuQC zH1!FF&K-(L1ih|Vt|^CYH#60$4xzIG^F>dToUN(@-Jy7#aD-M5J9z5xY;+9AS9}sn z8L+W2a|W6;bchAT;-Pwh(V--0?&Z#e;RyEr=L@y)ZrPOrth$M(G2c!lCW8er`htqs zq2@C8*hjhK(i26FhJ0!YM6b1eZXPHLGxOt8be|g(*+fptf1o@C`vWdmA_+Y zxqC(d-qI|UIMLJxU-OL~@~97SZxK|iuR*}W=D24QrlzP+x0YGXzT9lLShJsbT^>^T z+8qtKtH)w=>n^gJWZQeC_&93BcDl%kaGirb!*iPmerw4CddlBgfSXC1Upsg;)mLNE zS3}U$x1sGSmD}9c96669m$xl9ZgGy~?GyUD97umZgLJ#=*{mM4^#~R+`@qDtf+LP$ zv7P57PgWCruWDo`%NvhYg>7lc2eb^9z`<{MZdBUp;NIZh*l$acZ`){W^B1cxdgq2# z?%wzw)T2f&hcRi16jMN zA=U9F=3|7g`C>?e?^t(ri`pc^E#~c9%#fgD;EnagEY5$M6r5X@kW#gMDN#Jvm>~N| zUvbj*l{jSI`Qha5T9uMSYn%tX;tEa(keR4Rv=^--PFfB1B-B)sVLe4ezF7IBOEwav{0 zJpg&U45quWh*F3mdv}NSyRaTN<2 z67sd@y_y|&BHCI;HgjQp)MwFm!_6qjzcOMrjSy0Fmi&bC(EjZrlhn4P9@e~9ZFBt% z0M}ZjWLQbh>&~k(N3X$KLRKx1IwnTB~XUS}*O6 zmOG)1xrCZ?%T#4NzhV|r(<`cc#wrc-I5OB15NY8`(|TiSKy#=p%AWN5!P*otmd@29 z=u)^VHpZ%G?S1@%CYaD%GyZGP_@YIQ%ZMbgqzO3~H*h6S^vK4Y$nF`Ix^(fWq6C`W zK#C6!*H0;f9~*169ns)`@>{>Y;bQId^Y}WJF3}@Mwe9)Qf;J4Fvb;XJb4wuvzD2o= z336Eu`j96fw}bzq>7xT2C4^Fut zm6E&~Yqo%X#ZK(bk#Y1TgmA=OJVH;3+)Xbq2FLFw9=iQI-kvdn=RU!ezPDfU^b}u{ zE%5*a-&`H&#fp-w^f~R8 zi|)*W{81|dU0lW!#zc4@6k}EKyL-1}$BMLv%&I0U4O2&@WoHH0K4p%QKm3dLDFj?M z&q4uZG0H`@oqVS6TTGVQBDc5NcjVzVdFi>4>E@-Q`Y{m^8M|F+EixU>C)AtMLmm`gp18@*Y$Q`gegUGtSmDsKg$h) z`N-q9+WRCd#EyJf?~BB|>sdA=!o~(+>j8Yl`UPR2k%u2Bv_Kt_9*;v*R>`~j-h^b( z!~+s0U|UP_4@ER;h*v*7tA@g@^H|XtyKyKu^@p9@kmcr})ztDHiRDxZU91cUu9t}v z%bC6$3LmPxM@cbBT@-Ghj?e}(PAjXUq9m3O)O%zqZ^=$4F~rbR z&~`*_i0tV0fbTR$ANe$P&VgcEJ$X8tX%Mt~Vrq2R^Ey~n*;>0{do&{kLGY^u4p?CC zFk*Q07*TNlXG9$S2oKXzFxO0;>nok3v8)tf^4bg>ro<0m7fj@tGItZtV6v#T)z{Xe z>9?~%{Ff?=FLEeKsG<6(I1qYJha{Nc$zzA8s%T3h3Z~cw^VG3>Ov5tD!U1D61 zG}Hp(gJ~tiS>+~wd9RO|bf3*DxT#H=J274<2GDv1xyfO9!6_A(1GdjK(Sc393jRCEqUFdv%Ch@R zn$!TM(Rj!A61Wp{s~@7tPOf(8@B*~?hINQ)B1k#~gD2P2sWwnGkQ18Fp z88G|Yqs4@aDy=uphvbcBTN4IMf_bu*zS)W+Xl6b6#@W z&>{5B8Jot@>S?nj!;!s)-S@+BjF`q4$k7f3ml$ZnLhvs`Jaq#ZmzdcVZ5XSI)$Lo= zmJM60)jMK5ip>_>J%R2mAG$gk^ob)yLz;No@YB`tc9VuN1xAjH!eWK-ud(EB_D?I{ zP(3(})$uVRsq{uc^hBh?QZ#eB3i98&eRWa|@YS$TYg= zc)Yu=OvxE1PDSUINVswPb_+#VJ#1>o;e6NSI&$NK|8^==bu3NqI6VAJVKz zs*-`JA`W2(>6DYV;2O?U4;RBfjoNl*?;5YLI?%1$m*B`?UYHYnP`Q`!V|t14II%6O zvX{}GrvdmJ6^0$6NQ&oy8UjAGvoxb$Mt0*(oMiRHw_c7RW7QP<6?05h`fwd^MEwdc ziTP^>PuFLEIcmGU*Up+hquwmFH&+nHoDwNmG0b1u?Mgs$u7{V88W5@+GD)XrSV0I~NBErfIy+&L8&v$TzfTwu zM~XQ{hp6uLnQ@D{uWhDpoY*_LT9=;d+XKU#dh!`g*T0#K#MsYJ!jOfpcb+=3VzMYO zsR$%B#<>nDsDcphm=A{piF%PrsWa!{BsMsd!ILO8MM;j2-`+<*TOMN#3n`X|Ckpb9 zFYu0HI_t}a+%8Vv)*VC|uJnn~@qAP;0eo;htVqed2Hz2b!D`>*Z>flIAMft=Iqmfg z?zcp^%IWcre`UtKx_62kaS42VFFmklXHlL!!&P4)86Bb)58NFkQYRza&1Lk3e~=$g zP@XEj5yF%k5@M5nPGP(HL`r5+NGcfV7)q^&&AZ183s|foU`~$i>vc^`U*nZ#QFuGPrs3}U_N_$WX7UU@8T?0>eD}WK1Hu)^@A=s=U z+~=%n%c^tWJtB3KiXyo7$}oP27rOu~QEkwJA;G@D_(G^$^8SUT{ALe2czFGKi8@`z zNVI!jLd{aAnIV%{sL?D0dO!9W=?1taceDost@muqz%Wy7i{71x7Tsfd>2`O$xmjvw z4~D;A-~PrbeNU>s(6fGK)NqVuBwvesk^&Wl#MYzjT(OPqeLm)uB+55I@HZ31Jke63 zNL}Te#WJ1+_D$~#!io;Nva_`kwZ$=rEb&pyyYf6HJnG0ydAp`eKYFy)k zLwxjYC;O|UtH$$Ox|%qkZD*9p`w|h-0yD~0_5nvi)b4QerXB6@?lUWo#okn_;OTg; z(%a^IP4oOG8|Xv$l~Lp~WAKpTj)OIsB8cOz7`!?y|KZmK7?yA@4;Z15yL^)9WW1%s z;HN+mI89C)`Q%-~0CwYOnB-S)Y3oZaCf;=0&_~{_!&pQLV`ZU$Er%d4hQ=nJjMdOZIk$&LBa;%*#?^7Z1nNz|vznTu!<-h)z+Ay_>`SVUv**1< zB8M1W%tV{7`JmO8cdxtbO^LbPIaK%Kawoe~h>s}qu z6qQy*wv?}+C@Va_{e&3^U1>c)wAr@?{m2UO9@!l(^`&aGI19q zNEa}JeL-jNiSUZT*FGlHlN>!;eONqKDe|UxWmGaJO38_zVwgFDzKcuR#RyDokUD$c ziDmCT4Q3*@hN-YQEeAZdQIsR(_NXO6&`H*UsYn}KyTeuG7pels762#D zT@vheDq$vT%nd&FYkJh|~XE@OYcK>$R#LYo&Q?Fx)hdHepPj&Kb=8>2> z_@q2`TClfw@x!UO{O5dYdN)4zU4PW;M-G`o$=I>w6bgeJsC!eIs7j-;yL<4Z?vcp8 z>8J$E(BySj6Z?afg1jqQ{%0-6SoBSUxZ##w0qDMblZNZ2F;UFS?8( zThW2KFC|gasjYfq**s+8%?Y2bCW@2*D!$W)yN{WTh@`2w_)s)lPxZy`P|B-V;LDf0 zU$Z_&xbZTFA+r;WY91%U8%T)?bygzA^_Hi?fpCwbH$TI&SB9<` z>t4coR?@43N;9{{((Rv6E}y1WLwrCDKCW*YRPaU*z;O-m9NV=#S(FNJog4xcU_`|t zyzW|*&CR0HH?D3cW-43Slo{NM1s*SPSotYv4JYd=o_wqa@65bw1dd4qGRbkx=cN1z zMW09H%=RQJe4{){ezS>iwJ)gjBKsja>$NYRcPt3XnHMMefiW}{zBkuCBft5+xc9Y% z0p#+r7CS1;m!}2Z>Bs~Wrg7k%FDMovZwywclk?13BHWz^FBp!j(`Wm#K5k7ly~YVj znaE5&b2$%2!n$#i$;0NbZ0&9ntPne65#&j@uhb~=1=DpzTPmspEsO}MEI}LG)}i8N z1_SWBl(+|}36~Eer1V%~Qi^kTw`E#sTrPko_&`i&P6?$(`*6aO)SCePki0>CyW0$)y5wZ6eZeyIe9P%q()PgSoYxv*&uElU7Lh&NnXx#>3>8l zeFV`g{1F-NaamJj&jiIvQ*xb-A}aKSy_Jt~q8ei6+i>ibcb{}s38c5B$|S3SW6zLF z2yDi))iPkx$L}1fz8}}WTBaQoxM*Ur8-M*Z>TG3O_{OE%?OKir@d2mIpAFfUDKd?X zE{$^Coc?mcBVyAlcB;-0{xDyaD~w%m9+SFe}U8R zB~JV(Wt9Av3&n5mc)C>|-#CjD+Cthrx)kVi(-`2poN6A~^zmu==CZ}A9a=U$BuApE zX_Xh#5RWd*6v|C{iYq3~6WA4bYd5y3G&c z^C*pXh?;Q0+JQ@s?cQSvx4LcrOCAxJHkhy}TzFO6isL|mLPbO0~tw!+Jj42yn zZ%YfhPvfVp&!n7fWi75u3>xoVuE9%cnFcg)&GZ{fl}xL%=Bk|IX=r~;=c+gSFppP& z=W=q2(sQGCMGEjwhN8YfU+V^X)jepVC~z_>jXRhwhMkx4_|+3F+E68^eK!wLr6cv=G6ua| zge8foW&@Btg|G`A!|8v_v)h6_QcC2rEKB>S$7Y?SfrB zY}2OK^+_XB@tQ3(3gV>%>>>f|p(!UBwF4_VpZabY;+7gNq;1(4N^xr``-vki zUd)MQeC?m3^6>ZF%7F`s(zK#ZDE| z$>0HP(@^>g;{j=c%hCa(?v}e8ZXVYy-Y&N4K9wkA^e?{4zq}Vm>S+-)Q(sm#NIaxL z)pFenE*l50S_(hJ8 z6xWdnH-b-@&@1j#wtA|Z_m~DxvN}BFYfCTc8tN5yfR78p*CronkDkw_t}8SQj(e^W zbD`BzuYvV5Ri?=G9UcaC%IYut$bj_irNTz1WC6O+&lZxK`KWY#jfTuL+xC_rpGQZt zjzIbE^aPUHws0s;4tZWUbyu{Z(PDeLxosgx_mdp_>=OpND)l-`5hz&crV=o4$!pcvJ4&Rb;LY(9zKgt18(|bik67DLpp8s41TR973f+oz_J-_-$)&Ggs zRKxM1uz5{b+Jnls5L51E8;!7__faj+qU#=5y+Xp}E;Q$Q&{EP?5Q`aDPLT1(!y7|QQW~bCu??$3Ga~_+ zul>`Bbf_%FFI^=KmTM3!x_wt=#!i0msKUJBM#ywON|BVI;Ka#7CPmGB1YYnIC7toi z&}Bw?C(4MBh4wAJg3$!`k2BBggSASZePq`DSfqPRC<7`0tlT89@^RjKPr97Gjba_0 zo4Tt~nQ{mwQKh&XP7Jf5YPYD-QN(1${m|4ZrNaoVhw!UohR5FI%e8|i!6{Dyj#xX^a>ch@ znQWOhh6M~Kt<|3J>Fr$}GPkI5FDjWC;2-H85Kn1k%$%>F<$#g|Il1jF`T?HjL9dP7 zix1bgJdc39+^BkZ3$A|Al0+RZrx?a7zT!dE;3V<3(&I++`k^PPTPKd`bHI~i84n!_ z`{K`cX+|!wi84k}nObSyiTvvAUGD|Gpj*3}%tKFBCK!C(km$siw&6JYs+%8Ux{p13 z-bnGCJ*`_6VBa~S_xosiz-AO87}tT9CS84FqD8~e)z$8fF} zAm{DLk3v9dgj7VtBs`71H~!#0Mw5-w*tcQgb5g08#UuLp=e$g2@XNC$$%2B+6^?N4 z!G@~5`E`GoOvP5d=8Z#Hx1%-9ZoO7F0r4C?OQw7{&?a2+;d=%0q)?4ZC`urm6UwQ! ztDMMtB}3qHg)@K2o>>Q-qW8N-hwP^LWy1dt8`MT(sFlw6RK@KJwKktG=&9pY-1&27 za?<-If!Fi1zS%p4x6D!cL^t~awE8W>t~sfT6o?iGq#SxdWJxFGYeAJ=>wo;AC)C53 zl_&fL>LD|t7Jpn%v?u1tCQk-bC4%;j-dLtMPhoCne_xftJAkJ>dNx=uj*AQ5?;!y^ z=Y$5Yo8)2UNPEQx)| zDdw<@fn=o82oycJcYKg>*7VG8<{oDeP?HOv*zI|CEhveg2QR$5~wV_~m()y@tn(L7l zRy*8GZj>lY4W-oPeRkTNLn;FE5n|$s7JxEh98iYjS&;ivkSkltSw1B@BT^>KcCqnU z`}{Fq&xM>Do;FaiPLLGQheIf7Xdv}tDNIM*?4Eo`;|3bPUi7xESbnndSe~|v07OMG zS~TxHEm*Grk((2ftFhWokMMa^InXofbKkPKcZur(QQ$t0#4|?(EVee9+vR5L+RcL| zJkxXrNtnbH`M~;)o`oBA?*^h>NUhf-N2Hs^w8=s(ZcT@CPC-j3p8IY4AEa zB{~LBM1<4qhD0u+jze$4jsfDPz{yy|`2rA6M7{n8OSgBt?)SCyh#8pa=x%r;=xWvN z5dkCI#5HMWpkzVQn{3V#pp+K{CwdUN$ictz4zXasbcA zr1gZUFXis`kPY!EO4Cj?Oys^P6|&&5z&uo+flro)*pA0%%RQ+jaccuHbiIml z4*EuD(QQXC`O$5wAHkd}MUt*nkBQP%o041-XDAv88=5MOnHuX{RNd5Ljh=_<Nwj%7#u0)5%eWs~TxnfDOGR|cW=a21C-kEQxe zx^H@+NjBJ;=P#_HWh{>Ml4>3Q?svrcx&6#MuW-1PtwvqO9uCeg2YTk6Bfe!eq4d1< zsf?XQ*xx z3clW}{=@ZTcl^mFeOvV{F-aW2W*K1_Se3?qk<-RVly7Ka&oWbaNR@?rQ*#oDLa1PW zRFrSowGfxoYXeO;1_W8}e%E|F(rappX)r_S?c@ZmGCho{ev{MQO^6;w3X4 z-8EN{H;b=uEjky38;+bUAd$xw$A#07L0F8#me09UvV!W%{R^r+<7^qbQZa5WXDfVI zbKR52OPlEeF+Hn61J%MQt}Je~e2VVNX&=H9aLr6Z*9RJnSyrx3o4n2`*T}}C(b~~)_7p=_C zxhSUhqM>L6rrGgiVBLFj=WbqUHUki|R!zt4rsnm_f14FeZrYm)w2W%rzZ}CpeFZ0tDyrEe0jjfN!CE-s(5$Iu(ZYO{@_sMaTO1_aCuP z;BRZVzjm*z(b3Hk^RB1O=s(9$PQjKEXTOJeH1wSJ9bx^y%F4vk&(8 zgBKV4K{)=KJLdS|c>`oy7pPuamM94IWxBe^y?>-95(KzMG46i4`-s|HjDn)xc4m*3Xy4$dPRWUZtJuy*8 zZ36sOs4)PU)BO$6EIws`*-A~5Nw6uyH0LE=+1Vp4uLt}te85e6Z&F{GwHU4ygtMki zyV(EzEqX+E^Tx+JQU+Txm$iYR*I4WG*(&6I_a6MS zV5Rg+8^7AYn~Lq7MjsYURa6Fics1MSt}M47560i3LnZQEuX1wH5v8L>v-r_*kG}%> zAl-;qzz{R)t@H52rfdwYr(&dEn%xxi!e}QjVyR529W7@cShD%Wc4zNrFxy?OMK`CE z_rANhujP*tvN~t-!b|{1{pWN;H=&dsv`IehDjP@60kxywa`KhYwBPNu^-C{Xe5|;I zW*aVkKPwu}bl{aZhuFOdlm2OThuV|fP!e?b>-qDpR&uC<@>M3vxydJM`H!%3S~ziy zl%a>#AcGG-vSc6Zz55bfS4G}-3LQxtrObPGt4D?OWXq)r-omtny!ob~ARBsMmS= z{aNk510d0EHt-x6xS1gkRez5d|c;gRRt1s5LFk2Ya2<_~5bWe}X;>?e-W zuwGje^+(`J#EE@pGE)XiNXp@@earQw=v8XmndgfGAN1}+)pz!e^zJ~737_lK9hGCF z6~!?sVXxUvyY?3XKPXC(oWk{&p$5+p&&qgzeI5T*A5a~6UsdX7`KMFH@C$|l)o>e# z0_=73%7LLtctS)^ zG3cxE{b*0`3hnmgRC)JI4={?!AuW3wm?`O51TaTU1Rx2cMG=}BJ6wuy@G7CEXPe!g z30j;yl*R-=T{i|7oHVwGqpevQp(lo~vcJlR61Ef0?y@Fx<&<&N*)ifu2D8^rlvDTm zV3IgpE!nqsPM<%>!;*KWmTZ4b}-0ELI!_>wb7W5Y^{+U7)@~t9dFq ze0wSnhYUD$7|OtvLl8kLvM5gE0F?Spk6OdkJsBH?;Y(`M7bzeA3IT`ihlxui_be1Z(s>HaLQ(pO zo}V86uts^+Q<6^YH2#~7?cMqQ{Njk~8hPAs!oW9$oq9jk?(^_2YaXS89y>xnUpO(Y zWM5@9*RGnvM#$JYmqg4cIe<{4^y+kFU#Y=;3lB~u$`KPK(ye@gM@i6M->UL{{4spl z%uV}6F@qES?^0v2d9(XVB&TG3qjJj~=bYpX7|d}0EabDPzDP;q31>dNbU~EsZwTf* zuIl%7)z77IzC`m?*_0Ho7I$N)!I(G-((5qt{rO7a%(p;va8bJ4UkuBcR!D*yVlm`8 zE{qLm`HpoQcZyv?`_Cj6bY_L^{=JE(lCrrNam6C7-C%*O5HP6q=ym9^R4TfRo!Yd? z+J^t}yMON>GV+V2u`Ori)XPbbxWnNu?vV#<@DLM8Pa|iE`%#lL&mKa#c#Czh=RN6t)4WY^Ynzy6wP;f6lasu9P@8zzi9XIeE^@ zhV`NdSc(;ww$yAsYbU#@rGaJ{#ZJTfC<_ zDYex;!itOgTq7)nv#qep{0szKP!zn1o6ebmX=rnWL+)Lu8+@oY*t3Skhhf;eR030u zWn?YBjq6Es5A6HB^|e{|VEf$NST7XbhMevx3p-R;{KX71cF$rd%JUTdo@2j18vdUi zA4X$0offi>=iJXp-2AR@L>A^H=e-)8QvT^bzItmgezOe?f6S7CrXjNWe9U#ax0@c; z=9463QGrW$%Lv*un`1H2md}Ts)Riq5$rXwNyb&DuE(dJ42@c3W7C-L^ryO$W?X4ub-Cj>t(AbDM z+3B4NZ~vm{D-n`G?9T(+y2yF$qXkK%uD>|E#p=^L*r*;n7(VS3eLF7BDZC1=$K8v@ zKkR9C54Fem@}_XFFVHMH=&6U4c{7rnNoZP8gJ_BDQC> zJa}MK0ahw!;h`b^x%oYkU7PScL-Cr+<`Y3l$7ZkMtEp(N76kMD`&N?kF*<*-^Y=hf7YzqX@1$!TQ?^G4@Q?fdwW zTJ^`_W$G*HU*|&2Vmw8I-zyIkZksU*>8h3K--wr;B3XG7 zIP0M{;#v}Kw+9zuf^D@&^6XD_TGZCR#FWWs?hKB_(xARlDq*d$g-hrOi<7%AZH&^@ z4`PxPLRVvTPvrzN{4`awHm6fI!^bl01b`mh{te<(5ZFoLL~~+AQw$o;8jTByOI+0A zzTAm&&|>Y#ex-(p&dcOTXXGINM{}!tb#LD64_3DtI>aS| z6XJLNK+Dt#Wvj1QHpNB#fTEUJhDnd9V+xNhhccsjzDlUo(PBU>BVJsu#P-5*r#=E* z1i>yT@l!sBV;dQ6ROAE=-?<(RtDWTrhTAJ#z08%0 zf~$egdekf^;1A5dDLC)=+jr+}GWtY90iJ9;ynmGV({V*=@aXa&rZ{WWo^{jO`z@U8 z%}G5Qj)$l966d93Mm_bZF{oklx(eb#UKnGg*8=lB>9;dMHUu%=xZ=V(pQT`oyp$A z9cCW$-xWHb)c^L6&z}FLYti^_L$MPsT0qY-3B@3;;4)Nz@6S39dIoFz8w;CW`MEZ# zrFKfyo9b0`Y43F5u#s{_7E~8CC)0y1KZGt}t}o;bZq5h#C1ym8&cXJ@$1I zI;(jC?-V{eQmW83owga_Kx5>eqE^3tX|!SffPr90JyF@2O6AJ2;{n*1jRwl0aW$Ay zyVDXQeX`g0zPT5tF)fx@K^pak(J{H2mt|-_w~==XIk9U^QU8F`GGm^YJ;haS+qZ+7K&un7d+ zRJT3`G)%eJlxyVP7MF^Z6FYsEq56rI68B7yNWukSe#HXMfhJw|Dikn;+d6vtC{Ff$ z*6B(H-H;^}zPeKT38no&BOu8JFD0pH#e+TML3-g|D?ADG-q$zu$}mlUaS5-&aeg8{y>1D>}31x(iEEKW5$Cq zHsjCs&6?H%kke@SQm4k!t28IwFWra=mx@WFmk-iYZ16Ip1er54TM|YH!sIkpqSf=g z>pLB#)M|_4-Y7gEK(Y)$Z~aV(1P(?h z2!1uco%U+5z?)&R>BeOXQ{`vm*cLjrO%FN9xoWk?OJw- z2ACEyRMpHH9)0>Mciu)}^jBXat@>~qzUYT36UH$F$$pdFr})NA@8G`7@w(W+E+kIK zbj#3Q%?tFg;_&H6im|N^2sekzOTsQNk)05w*o4IWV|l_yKAV#&t&rMcY8VcyHkwq& z`X#Qret$F#7KpKzm1JUKl7m=%gl9lu!?-)2yWkJ<51+aS5=ScMF2tZmHr-Xex8>(D zq>SA7)T~*3hxw7xld(PXvn0HX_Q1L-Ag+vKD~Jw0$dy=mUy&`#ps^Dlf;KE6(QMCZ zlg7F}_pF1hZvr^{3kdd#)p1(Sf91cI{@P~aokU^Ly{~IB`>fVGfza>2CAYNp57lT$ z!^GtU&6UyU#pQ)IL00XUes}sG^h`sB09^odW)kxLGu+3|1jDg^H1xMJdpX!jp*6#E zEM<=HWTEF%E0`)8KCL3u-jKAfcUjiZLUtYLa`<_0Ul-WSq0a=Q6|Ru@A9|(##D(O3 z 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 literal 0 HcmV?d00001 diff --git a/Materials/web.png b/Materials/web.png new file mode 100644 index 0000000000000000000000000000000000000000..86ea5b012c94d46653076f7dd7f9155cc05bc532 GIT binary patch literal 93304 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�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 Y!0qe0WolsG34r)hSJ6=}Q?d&BKPW$?-2eap literal 0 HcmV?d00001 diff --git a/Web/README.md b/Web/README.md new file mode 100644 index 0000000..1724f4c --- /dev/null +++ b/Web/README.md @@ -0,0 +1,19 @@ +# [Trivial.Web](https://trivial.kingcean.net/web/controller) + +ASP.NET Core extensions. + +## Import + +Add following namespace to your code file to use. + +```csharp +using Trivial.Web; +``` + +## Request + +Some extension methods to get the field from HTTP request. + +## Action result + +Some extension methods to convert some modes to `ActionResult`. diff --git a/Web/Web.csproj b/Web/Web.csproj new file mode 100644 index 0000000..bff6b4d --- /dev/null +++ b/Web/Web.csproj @@ -0,0 +1,32 @@ + + + + + + net8.0;net6.0; + Trivial.Web + Trivial + Trivial.Web + A library for web API. + true + true + snupkg + web.png + https://github.com/nuscien/trivial/raw/master/Materials/logo.png + web mvc + + + + ..\bin\$(Configuration)\ + ..\bin\$(Configuration)\$(TargetFramework)\Trivial.Web.xml + + + + + + + + + + + diff --git a/Web/Web/ControllerExtensions.cs b/Web/Web/ControllerExtensions.cs new file mode 100644 index 0000000..8f556aa --- /dev/null +++ b/Web/Web/ControllerExtensions.cs @@ -0,0 +1,913 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Claims; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Net.Http.Headers; +using Trivial.Collection; +using Trivial.Data; +using Trivial.Net; +using Trivial.Security; +using Trivial.Text; + +namespace Trivial.Web; + +/// +/// The controller extensions. +/// +public static class ControllerExtensions +{ + private const string NullString = "null"; + private static MethodInfo method; + + /// + /// Gets the first string value. + /// + /// The form collection. + /// The key. + /// true if need trim; otherwise, false. + /// The string value; or null, if non-exist. + public static string GetFirstStringValue(this IFormCollection request, string key, bool trim = false) + { + var col = request[key]; + string str = null; + if (trim) + { + foreach (var ele in col) + { + if (ele == null) continue; + var s = ele.Trim(); + if (s.Length == 0) + { + str ??= string.Empty; + continue; + } + + str = s; + } + } + else + { + foreach (var ele in col) + { + if (ele == null) continue; + if (ele.Length == 0) + { + str ??= string.Empty; + continue; + } + + str = ele; + } + } + + return str; + } + + /// + /// Gets the merged string value. + /// + /// The form collection. + /// The key. + /// The splitter charactor. + /// true if need trim; otherwise, false. + /// The string value; or null, if non-exist. + public static string GetMergedStringValue(this IFormCollection request, string key, char split = ',', bool trim = false) + { + IEnumerable col = request[key]; + if (trim) col = col.Select(ele => ele?.Trim()).Where(ele => !string.IsNullOrEmpty(ele)); + return string.Join(split, col); + } + + /// + /// Gets the first string value. + /// + /// The query collection. + /// The key. + /// true if need trim; otherwise, false. + /// The string value; or null, if non-exist. + public static string GetFirstStringValue(this IQueryCollection request, string key, bool trim = false) + { + var col = request[key]; + string str = null; + if (trim) + { + foreach (var ele in col) + { + if (ele == null) continue; + var s = ele.Trim(); + if (s.Length == 0) + { + str ??= string.Empty; + continue; + } + + str = s; + } + } + else + { + foreach (var ele in col) + { + if (ele == null) continue; + if (ele.Length == 0) + { + str ??= string.Empty; + continue; + } + + str = ele; + } + } + + return str; + } + + /// + /// Gets the merged string value. + /// + /// The query collection. + /// The key. + /// The splitter charactor. + /// true if need trim; otherwise, false. + /// The string value; or null, if non-exist. + public static string GetMergedStringValue(this IQueryCollection request, string key, char split = ',', bool trim = false) + { + IEnumerable col = request[key]; + if (trim) col = col.Select(ele => ele?.Trim()).Where(ele => !string.IsNullOrEmpty(ele)); + return string.Join(split, col); + } + + /// + /// Gets the integer value. + /// + /// The query collection. + /// The key. + /// The number value; or null, if non-exist or parse failed. + public static int? TryGetInt32Value(this IQueryCollection request, string key) + { + var s = request[key].Select(ele => ele?.Trim()).FirstOrDefault(ele => !string.IsNullOrEmpty(ele)); + if (Maths.Numbers.TryParseToInt32(s, 10, out var r)) return r; + return null; + } + + /// + /// Gets the integer value. + /// + /// The query collection. + /// The key. + /// The output result. + /// true if parse succeeded; otherwise, false. + public static bool TryGetInt32Value(this IQueryCollection request, string key, out int result) + { + var r = TryGetInt32Value(request, key); + if (r.HasValue) + { + result = r.Value; + return true; + } + + result = default; + return false; + } + + /// + /// Gets the integer value. + /// + /// The query collection. + /// The key. + /// The number value; or null, if non-exist or parse failed. + public static long? TryGetInt64Value(this IQueryCollection request, string key) + { + var s = request[key].Select(ele => ele?.Trim()).FirstOrDefault(ele => !string.IsNullOrEmpty(ele)); + if (Maths.Numbers.TryParseToInt64(s, 10, out var r)) return r; + return null; + } + + /// + /// Gets the integer value. + /// + /// The query collection. + /// The key. + /// The output result. + /// true if parse succeeded; otherwise, false. + public static bool TryGetInt64Value(this IQueryCollection request, string key, out long result) + { + var r = TryGetInt64Value(request, key); + if (r.HasValue) + { + result = r.Value; + return true; + } + + result = default; + return false; + } + + /// + /// Gets the floating value. + /// + /// The query collection. + /// The key. + /// The number value; or null, if non-exist or parse failed. + public static float? TryGetSingleValue(this IQueryCollection request, string key) + { + var s = request[key].Select(ele => ele?.Trim()).FirstOrDefault(ele => !string.IsNullOrEmpty(ele)); + if (float.TryParse(s, out var r)) return r; + return null; + } + + /// + /// Gets the floating value. + /// + /// The query collection. + /// The key. + /// The output result. + /// true if parse succeeded; otherwise, false. + public static bool TryGetSingleValue(this IQueryCollection request, string key, out float result) + { + var r = TryGetSingleValue(request, key); + if (r.HasValue) + { + result = r.Value; + return true; + } + + result = default; + return false; + } + + /// + /// Gets the floating value. + /// + /// The query collection. + /// The key. + /// The number value; or null, if non-exist or parse failed. + public static decimal? TryGetDecimalValue(this IQueryCollection request, string key) + { + var s = request[key].Select(ele => ele?.Trim()).FirstOrDefault(ele => !string.IsNullOrEmpty(ele)); + if (decimal.TryParse(s, out var r)) return r; + return null; + } + + /// + /// Gets the floating value. + /// + /// The query collection. + /// The key. + /// The output result. + /// true if parse succeeded; otherwise, false. + public static bool TryGetDecimalValue(this IQueryCollection request, string key, out decimal result) + { + var r = TryGetDecimalValue(request, key); + if (r.HasValue) + { + result = r.Value; + return true; + } + + result = default; + return false; + } + + /// + /// Gets the floating value. + /// + /// The query collection. + /// The key. + /// The number value; or null, if non-exist or parse failed. + public static double? TryGetDoubleValue(this IQueryCollection request, string key) + { + var s = request[key].Select(ele => ele?.Trim()).FirstOrDefault(ele => !string.IsNullOrEmpty(ele)); + if (double.TryParse(s, out var r)) return r; + return null; + } + + /// + /// Gets the floating value. + /// + /// The query collection. + /// The key. + /// The output result. + /// true if parse succeeded; otherwise, false. + public static bool TryGetDoubleValue(this IQueryCollection request, string key, out double result) + { + var r = TryGetDoubleValue(request, key); + if (r.HasValue) + { + result = r.Value; + return true; + } + + result = default; + return false; + } + + /// + /// Tries to get a property as boolean. + /// + /// The query. + /// The property key. + /// true if it is true; or false, if it is false; or null, if not supported. + public static bool? TryGetBoolean(this IQueryCollection request, string key) + { + var plain = request?.GetFirstStringValue(key, true)?.ToLowerInvariant(); + var isPlain = JsonBooleanNode.TryParse(plain); + return isPlain?.Value; + } + + /// + /// Tries to get a property as boolean. + /// + /// The query. + /// The property key. + /// The result. + /// true if parse succeeded; otherwise, false. + public static bool TryGetBoolean(this IQueryCollection request, string key, out bool result) + { + var plain = request?.GetFirstStringValue(key, true)?.ToLowerInvariant(); + var isPlain = JsonBooleanNode.TryParse(plain); + if (isPlain == null) + { + result = false; + return false; + } + + result = isPlain.Value; + return true; + } + + /// + /// Gets the query data. + /// + /// The HTTP request. + /// The optional encoding. + /// The string value; or null, if non-exist. + public static async Task ReadBodyAsQueryDataAsync(this HttpRequest request, Encoding encoding = null) + { + if (request == null || request.Body == null) return null; + encoding ??= Encoding.UTF8; + using var reader = new StreamReader(request.Body, encoding); + var query = await reader.ReadToEndAsync(); + var q = new QueryData(); + q.ParseSet(query, false, encoding); + return q; + } + + /// + /// Gets the JSON object from body. + /// + /// The HTTP request. + /// The token to monitor for cancellation requests. + /// A JSON object instance; or null, if no body. + /// json does not represent a valid single JSON object. + /// options contains unsupported options. + public static Task ReadBodyAsJsonAsync(this HttpRequest request, CancellationToken cancellationToken) + { + if (request == null || request.Body == null) return null; + return JsonObjectNode.ParseAsync(request.Body, default, cancellationToken); + } + + /// + /// Gets the JSON object from body. + /// + /// The HTTP request. + /// Options to control the reader behavior during parsing. + /// The token to monitor for cancellation requests. + /// A JSON object instance; or null, if no body. + /// json does not represent a valid single JSON object. + /// options contains unsupported options. + public static Task ReadBodyAsJsonAsync(this HttpRequest request, JsonDocumentOptions options, CancellationToken cancellationToken) + { + if (request == null || request.Body == null) return null; + return JsonObjectNode.ParseAsync(request.Body, options, cancellationToken); + } + + /// + /// Gets the JSON array from body. + /// + /// The HTTP request. + /// The token to monitor for cancellation requests. + /// A JSON array instance; or null, if no body. + /// json does not represent a valid single JSON object. + /// options contains unsupported options. + public static Task ReadBodyAsJsonArrayAsync(this HttpRequest request, CancellationToken cancellationToken) + { + if (request == null || request.Body == null) return null; + return JsonArrayNode.ParseAsync(request.Body, default, cancellationToken); + } + + /// + /// Gets the JSON array from body. + /// + /// The HTTP request. + /// Options to control the reader behavior during parsing. + /// The token to monitor for cancellation requests. + /// A JSON array instance; or null, if no body. + /// json does not represent a valid single JSON object. + /// options contains unsupported options. + public static Task ReadBodyAsJsonArrayAsync(this HttpRequest request, JsonDocumentOptions options, CancellationToken cancellationToken) + { + if (request == null || request.Body == null) return null; + return JsonArrayNode.ParseAsync(request.Body, options, cancellationToken); + } + + /// + /// Convert to an action result. + /// + /// The value. + /// The action result. + public static ActionResult ToActionResult(this ChangingResultInfo value) + { + if (value == null) return new NotFoundResult(); + var ex = value.GetException(); + var status = ex != null ? (GetStatusCode(ex) ?? 500) : 200; + if (status >= 300) + { + status = value.ErrorCode switch + { + ChangeErrorKinds.NotFound => 404, + ChangeErrorKinds.Busy => 503, + ChangeErrorKinds.Unsupported => 501, + ChangeErrorKinds.Conflict => 409, + _ => status + }; + } + + return new JsonResult(value) + { + StatusCode = status + }; + } + + /// + /// Convert to an action result. + /// + /// The value. + /// The action result. + public static ActionResult ToActionResult(this ChangeMethods value) + => ToActionResult(new ChangingResultInfo(value)); + + /// + /// Convert to an action result. + /// + /// The value. + /// The error message. + /// The action result. + public static ActionResult ToActionResult(this ChangeErrorKinds value, string message) + => ToActionResult(new ChangingResultInfo(value, message)); + + /// + /// Convert to an action result. + /// + /// The value. + /// The action result. + public static ContentResult ToActionResult(this JsonObjectNode value) + => new() + { + ContentType = WebFormat.JsonMIME, + StatusCode = 200, + Content = value?.ToString() ?? NullString + }; + + /// + /// Convert to an action result. + /// + /// The value. + /// The action result. + public static ContentResult ToActionResult(this JsonArrayNode value) + => new() + { + ContentType = WebFormat.JsonMIME, + StatusCode = 200, + Content = value?.ToString() ?? NullString + }; + + /// + /// Convert to an action result. + /// + /// The value. + /// The action result. + public static ContentResult ToActionResult(this IJsonObjectHost value) + => new() + { + ContentType = WebFormat.JsonMIME, + StatusCode = 200, + Content = value?.ToJson()?.ToString() ?? NullString + }; + + /// + /// Convert to an action result. + /// + /// The value. + /// The action result. + public static ContentResult ToActionResult(System.Text.Json.Nodes.JsonObject value) + => new() + { + ContentType = WebFormat.JsonMIME, + StatusCode = 200, + Content = value?.ToJsonString() ?? NullString + }; + + /// + /// Convert to an action result. + /// + /// The value. + /// The action result. + public static ContentResult ToActionResult(System.Text.Json.Nodes.JsonArray value) + => new() + { + ContentType = WebFormat.JsonMIME, + StatusCode = 200, + Content = value?.ToJsonString() ?? NullString + }; + + /// + /// Converts an exception to action result with exception message. + /// + /// The controller. + /// The exception. + /// true if return null for unknown exception; otherwise, false. + /// The action result. + public static ActionResult ExceptionResult(this ControllerBase controller, Exception ex, bool ignoreUnknownException = false) + { + if (ex == null) return controller.StatusCode(500); + var result = new ErrorMessageResult(ex); + var status = GetStatusCode(ex, ignoreUnknownException); + if (!status.HasValue) return null; + return new JsonResult(result) + { + StatusCode = status.Value + }; + } + + /// + /// Converts an exception to action result with exception message. + /// + /// The controller. + /// The exception. + /// The error code. + /// true if return null for unknown exception; otherwise, false. + /// The action result. + public static ActionResult ExceptionResult(this ControllerBase controller, Exception ex, string errorCode, bool ignoreUnknownException = false) + { + if (ex == null) return controller.StatusCode(500); + var result = new ErrorMessageResult(ex, errorCode); + var status = GetStatusCode(ex, ignoreUnknownException); + if (!status.HasValue) return null; + return new JsonResult(result) + { + StatusCode = status.Value + }; + } + + /// + /// Converts an exception to action result with exception message. + /// + /// The controller. + /// The HTTP status code. + /// The exception. + /// The action result. + public static ActionResult ExceptionResult(this ControllerBase controller, int status, Exception ex) + { + if (ex == null) return controller.StatusCode(status); + var result = new ErrorMessageResult(ex); + return new JsonResult(result) + { + StatusCode = status + }; + } + + /// + /// Converts an exception to action result with exception message. + /// + /// The controller. + /// The HTTP status code. + /// The exception. + /// The error code. + /// The action result. + public static ActionResult ExceptionResult(this ControllerBase controller, int status, Exception ex, string errorCode) + { + if (ex == null) return controller.StatusCode(status); + var result = new ErrorMessageResult(ex, errorCode); + return new JsonResult(result) + { + StatusCode = status + }; + } + + /// + /// Converts an exception to action result with exception message. + /// + /// The controller. + /// The HTTP status code. + /// The exception message. + /// The optional error code. + /// The action result. +#pragma warning disable IDE0060 + public static ActionResult ExceptionResult(this ControllerBase controller, int status, string ex, string errorCode = null) +#pragma warning restore IDE0060 + { + var result = new ErrorMessageResult(ex, errorCode); + return new JsonResult(result) + { + StatusCode = status + }; + } + + /// + /// Gets the query data instance. + /// + /// The request. + /// The query data instance. + public static QueryData GetQueryData(this IQueryCollection request) + { + if (request == null) return null; + var q = new QueryData(); + foreach (var item in request) + { + q.Add(item.Key, item.Value as IEnumerable); + } + + q.Remove("random"); + return q; + } + + /// + /// Signs in. + /// + /// The controller. + /// The token request route. + /// The token maker. + /// The login response. + public static async Task SignInAsync(ControllerBase controller, TokenRequestRoute route, Func tokenMaker) where TToken : TokenInfo + { + TToken result; + try + { + if (controller is null) return default; + var stream = controller.Request.Body; + if (stream is null) + { + result = tokenMaker(); + result.ErrorCode = TokenInfo.ErrorCodeConstants.InvalidRequest; + result.ErrorDescription = "The body was empty."; + return default; + } + + tokenMaker ??= () => Activator.CreateInstance(); + string input; + using (var reader = new StreamReader(controller.Request.Body, Encoding.UTF8)) + { + input = await reader.ReadToEndAsync(); + } + + var r = await route.SignInAsync(input); + result = r?.ItemSelected as TToken; + if (result != null) return result; + result = tokenMaker(); + result.ErrorCode = TokenInfo.ErrorCodeConstants.InvalidRequest; + result.ErrorDescription = "Cannot sign in."; + return result; + } + catch (ArgumentException ex) + { + result = tokenMaker(); + result.ErrorCode = TokenInfo.ErrorCodeConstants.InvalidRequest; + result.ErrorDescription = ex.Message; + return result; + } + catch (IOException ex) + { + result = tokenMaker(); + result.ErrorCode = TokenInfo.ErrorCodeConstants.ServerError; + result.ErrorDescription = ex.Message; + return result; + } + } + + /// + /// Converts a JSON format string to a result. + /// + /// The JSON format string. + /// The content result converted. + public static ContentResult JsonStringResult(string json) + => new() + { + StatusCode = 200, + ContentType = WebFormat.JsonMIME, + Content = json + }; + + /// + /// Creates a file result. + /// + /// The source. + /// The entity tag associated with the file. + /// The optional MIME content type; or null, if detects automatically. + /// A file result; or null, if non-exists. + public static FileStreamResult FileResult(FileInfo source, EntityTagHeaderValue entityTag = null, string mime = null) + { + if (source == null || !source.Exists) return null; + mime ??= GetByFileExtension(source.Extension, WebFormat.StreamMIME); + var result = new FileStreamResult(source.OpenRead(), mime) + { + LastModified = source.LastWriteTime, + FileDownloadName = source.Name, + EntityTag = entityTag + }; + return result; + } + + /// + /// Creates a file result. + /// + /// The source. + /// The entity tag associated with the file. + /// The optional MIME content type; or null, if detects automatically. + /// A file result; or null, if non-exists. + public static FileStreamResult FileResult(IO.BaseFileReferenceInfo source, EntityTagHeaderValue entityTag = null, string mime = null) + => FileResult(source?.Source, entityTag, mime); + + /// + /// Creates a file result. + /// + /// The source. + /// The file name used for downloading. + /// The last modified information associated with the file. + /// The optional MIME content type; or null, if detects automatically. + /// A file result; or null, if non-exists. + public static FileStreamResult FileResult(Stream source, string downloadName, DateTimeOffset? lastModified = null, string mime = null) + => FileResult(source, downloadName, null, lastModified, mime); + + /// + /// Creates a file result. + /// + /// The source. + /// The file name used for downloading. + /// The entity tag associated with the file. + /// The last modified information associated with the file. + /// The optional MIME content type; or null, if detects automatically. + /// A file result; or null, if stream source is null. + public static FileStreamResult FileResult(Stream source, string downloadName, EntityTagHeaderValue entityTag, DateTimeOffset? lastModified = null, string mime = null) + { + if (source == null) return null; + if (string.IsNullOrEmpty(mime) && downloadName?.Contains('.') == true) + { + var ext = downloadName.Trim().Split('.').LastOrDefault(); + if (string.IsNullOrEmpty(ext)) + mime = WebFormat.StreamMIME; + else + mime = GetByFileExtension("." + ext, WebFormat.StreamMIME); + } + + var result = new FileStreamResult(source, mime) + { + LastModified = lastModified, + EntityTag = entityTag + }; + if (!string.IsNullOrWhiteSpace(downloadName)) + result.FileDownloadName = downloadName; + return result; + } + + /// + /// Creates a file result. + /// + /// The source. + /// The file name used for downloading. + /// true if enables range requests processing; otherwise, false. + /// The entity tag associated with the file. + /// The last modified information associated with the file. + /// The optional MIME content type; or null, if detects automatically. + /// A file result; or null, if stream source is null. + public static FileStreamResult FileResult(Stream source, string downloadName, EntityTagHeaderValue entityTag, bool enableRangeProcessing, DateTimeOffset? lastModified = null, string mime = null) + { + var result = FileResult(source, downloadName, entityTag, lastModified, mime); + if (result == null) return null; + result.EnableRangeProcessing = enableRangeProcessing; + return result; + } + + /// + /// Creates a file result. + /// + /// The assembly with the embedded file. + /// The sub path of the embedded file. + /// The file name used for downloading. + /// The entity tag associated with the file. + /// The optional MIME content type; or null, if detects automatically. + /// A file result; or null, if non-exists. + public static FileStreamResult FileResult(Assembly assembly, string subPath, string downloadName, EntityTagHeaderValue entityTag, string mime = null) + { + if (string.IsNullOrWhiteSpace(subPath)) return null; + if (assembly == null) + assembly = Assembly.GetExecutingAssembly(); + var stream = assembly.GetManifestResourceStream(subPath); + if (stream == null) return null; + var file = IO.FileSystemInfoUtility.TryGetFileInfo(assembly.Location); + var lastModified = file?.LastWriteTime; + if (string.IsNullOrWhiteSpace(downloadName)) + downloadName = subPath.Split(new[] { '\\', '/' }).LastOrDefault(); + return FileResult(stream, downloadName, entityTag, lastModified, mime); + } + + /// + /// Creates a file result. + /// + /// The assembly with the embedded file. + /// The sub path of the embedded file. + /// The entity tag associated with the file. + /// The optional MIME content type; or null, if detects automatically. + /// A file result; or null, if non-exists. + public static FileStreamResult FileResult(Assembly assembly, string subPath, EntityTagHeaderValue entityTag, string mime = null) + => FileResult(assembly, subPath, null, entityTag, mime); + + /// + /// Gets the status code. + /// + /// The exception. + /// true if return null for unknown exception; otherwise, false. + /// The action result. + private static int? GetStatusCode(Exception ex, bool ignoreUnknownException = false) + { + if (ex == null) return 500; + if (ex.InnerException != null) + { + if (ex is AggregateException) + { + ex = ex.InnerException; + } + else if (ex is InvalidOperationException) + { + ex = ex.InnerException; + ignoreUnknownException = false; + } + } + + if (ex is SecurityException) return 403; + else if (ex is UnauthorizedAccessException) return 401; + else if (ex is NotSupportedException) return 502; + else if (ex is NotImplementedException) return 502; + else if (ex is TimeoutException) return 408; + else if (ex is OperationCanceledException) return 408; + if (ignoreUnknownException && !( + ex is InvalidOperationException + || ex is ArgumentException + || ex is NullReferenceException + || ex is System.Data.Common.DbException + || ex is JsonException + || ex is System.Runtime.Serialization.SerializationException + || ex is FailedHttpException + || ex is IOException + || ex is ApplicationException + || ex is InvalidCastException + || ex is FormatException + || ex is ArithmeticException + || ex is ExternalException + || ex is InvalidDataException)) return null; + return 500; + } + + /// + /// Gets the MIME content type by file extension part. + /// + /// The file extension. + /// The default MIME content type. + /// The MIME content type. + private static string GetByFileExtension(string fileExtension, string defaultMime) + { + if (string.IsNullOrWhiteSpace(fileExtension)) return null; + if (method == null) + { + method = typeof(WebFormat).GetMethod("GetMime", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(string) }, null); + if (method == null) + method = typeof(WebFormat).GetMethod("GetMime", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null); + if (method == null) + return defaultMime; + } + + var r = method.Invoke(null, new object[] { fileExtension }); + if (r == null) return defaultMime; + try + { + return (string)r; + } + catch (InvalidCastException) + { + } + + return defaultMime; + } +} diff --git a/WinKit.sln b/WinKit.sln index caa356e..91828d0 100644 --- a/WinKit.sln +++ b/WinKit.sln @@ -7,6 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "Common\Common.csp EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{03B291A4-6F6F-4A26-9772-A1DE02B5EF48}" ProjectSection(SolutionItems) = preProject + Common.props = Common.props LICENSE = LICENSE Materials\logo.png = Materials\logo.png README.md = README.md @@ -17,6 +18,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo", "Demo\Demo.csproj", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cli", "Cli\Cli.csproj", "{B356FDA6-4A2D-4FC6-83DC-EB2E576DAF2C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web", "Web\Web.csproj", "{FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Console", "Console\Console.csproj", "{99AC4C2E-6095-444F-AB5D-0E4E65C46B85}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -101,6 +106,46 @@ Global {B356FDA6-4A2D-4FC6-83DC-EB2E576DAF2C}.Release|x64.Build.0 = Release|Any CPU {B356FDA6-4A2D-4FC6-83DC-EB2E576DAF2C}.Release|x86.ActiveCfg = Release|Any CPU {B356FDA6-4A2D-4FC6-83DC-EB2E576DAF2C}.Release|x86.Build.0 = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|ARM.ActiveCfg = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|ARM.Build.0 = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|arm64.ActiveCfg = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|arm64.Build.0 = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|x64.ActiveCfg = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|x64.Build.0 = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|x86.ActiveCfg = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Debug|x86.Build.0 = Debug|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|Any CPU.Build.0 = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|ARM.ActiveCfg = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|ARM.Build.0 = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|arm64.ActiveCfg = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|arm64.Build.0 = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|x64.ActiveCfg = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|x64.Build.0 = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|x86.ActiveCfg = Release|Any CPU + {FD8946C4-AD7C-47F3-84F9-BB567E0F14A9}.Release|x86.Build.0 = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|ARM.ActiveCfg = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|ARM.Build.0 = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|arm64.ActiveCfg = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|arm64.Build.0 = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|x64.ActiveCfg = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|x64.Build.0 = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|x86.ActiveCfg = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Debug|x86.Build.0 = Debug|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|Any CPU.Build.0 = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|ARM.ActiveCfg = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|ARM.Build.0 = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|arm64.ActiveCfg = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|arm64.Build.0 = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|x64.ActiveCfg = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|x64.Build.0 = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|x86.ActiveCfg = Release|Any CPU + {99AC4C2E-6095-444F-AB5D-0E4E65C46B85}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/docs/assets/badge_ASPNET_5_0.svg b/docs/assets/badge_ASPNET_5_0.svg new file mode 100644 index 0000000..3103b53 --- /dev/null +++ b/docs/assets/badge_ASPNET_5_0.svg @@ -0,0 +1 @@ +ASP.NET Core: 5.0ASP.NET Core5.0 \ No newline at end of file diff --git a/docs/assets/badge_ASPNET_6_0.svg b/docs/assets/badge_ASPNET_6_0.svg new file mode 100644 index 0000000..b4f0f48 --- /dev/null +++ b/docs/assets/badge_ASPNET_6_0.svg @@ -0,0 +1 @@ +ASP.NET Core: 6.0ASP.NET Core6.0 \ No newline at end of file diff --git a/docs/assets/badge_ASPNET_8_0.svg b/docs/assets/badge_ASPNET_8_0.svg new file mode 100644 index 0000000..95d324d --- /dev/null +++ b/docs/assets/badge_ASPNET_8_0.svg @@ -0,0 +1 @@ +ASP.NET: 8.0ASP.NET8.0 \ No newline at end of file diff --git a/docs/assets/badge_NET_5_Win10.svg b/docs/assets/badge_NET_5_Win10.svg deleted file mode 100644 index 544b222..0000000 --- a/docs/assets/badge_NET_5_Win10.svg +++ /dev/null @@ -1 +0,0 @@ -.NET: 5-windows10.NET5-windows10 \ No newline at end of file diff --git a/docs/assets/badge_NET_Fx_4_6.svg b/docs/assets/badge_NET_Fx_4_6.svg new file mode 100644 index 0000000..e6290b4 --- /dev/null +++ b/docs/assets/badge_NET_Fx_4_6.svg @@ -0,0 +1 @@ +.NET Framework: 4.6.NET Framework4.6 \ No newline at end of file diff --git a/docs/assets/badge_NET_Fx_4_6_1.svg b/docs/assets/badge_NET_Fx_4_6_1.svg new file mode 100644 index 0000000..52e190e --- /dev/null +++ b/docs/assets/badge_NET_Fx_4_6_1.svg @@ -0,0 +1 @@ +.NET Framework: 4.6.1.NET Framework4.6.1 \ No newline at end of file diff --git a/docs/assets/badge_NET_Fx_4_8.svg b/docs/assets/badge_NET_Fx_4_8.svg new file mode 100644 index 0000000..4a19cf6 --- /dev/null +++ b/docs/assets/badge_NET_Fx_4_8.svg @@ -0,0 +1 @@ +.NET Framework: 4.8.NET Framework4.8 \ No newline at end of file diff --git a/docs/assets/bg_title.jpg b/docs/assets/bg_title.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b49f950e1b10b3424f858f3f595e8197a51e3bbf GIT binary patch literal 36664 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 L{adH(>xcgXK!HRC literal 0 HcmV?d00001 diff --git a/docs/assets/chemistry.png b/docs/assets/chemistry.png new file mode 100644 index 0000000000000000000000000000000000000000..866ba0f06a7c59c70e5f12dabce942d7a95bd1b0 GIT binary patch literal 28928 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 E0EFhEW&i*H literal 0 HcmV?d00001 diff --git a/docs/assets/cmd.png b/docs/assets/cmd.png new file mode 100644 index 0000000000000000000000000000000000000000..9996d5302e276306185b93a32c016a84911ee98e GIT binary patch literal 33226 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≧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 literal 0 HcmV?d00001 diff --git a/docs/assets/mime.png b/docs/assets/mime.png new file mode 100644 index 0000000000000000000000000000000000000000..7dc0d97cf5f05903c4da341b1e731ea7ea47ad87 GIT binary patch literal 30891 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 literal 0 HcmV?d00001 diff --git a/docs/assets/web.png b/docs/assets/web.png new file mode 100644 index 0000000000000000000000000000000000000000..05daf89dcf873a2c5a4657df5dc6450c1be2fcec GIT binary patch literal 31315 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 z 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